From 730a9c8809ca936b6acec9db60f297460787520a Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 24 Sep 2024 00:53:19 +0200 Subject: [PATCH 01/14] RegisterWasiPollHook --- eng/testing/tests.wasi.targets | 2 + .../Threading/Tasks/TaskToAsyncResult.cs | 2 + .../ILLink.Descriptors.LibraryBuild.WASI.xml | 1 + .../src/System/Threading/Thread.Unix.cs | 6 ++ .../System/Threading/Wasi/WasiEventLoop.cs | 87 ++++++++++++++++++- src/mono/sample/wasi/Directory.Build.targets | 1 + 6 files changed, 96 insertions(+), 3 deletions(-) diff --git a/eng/testing/tests.wasi.targets b/eng/testing/tests.wasi.targets index e076ac18c4b0b8..db27c71fcb20ab 100644 --- a/eng/testing/tests.wasi.targets +++ b/eng/testing/tests.wasi.targets @@ -50,6 +50,8 @@ <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasm --engine-arg=max-wasm-stack=134217728 <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=http <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=inherit-network + <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=tcp + <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=udp <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=allow-ip-name-lookup <_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--env --engine-arg=DOTNET_WASI_PRINT_EXIT_CODE=1 <_XHarnessArgs Condition="'$(WasmXHarnessArgsCli)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgsCli) diff --git a/src/libraries/Common/src/System/Threading/Tasks/TaskToAsyncResult.cs b/src/libraries/Common/src/System/Threading/Tasks/TaskToAsyncResult.cs index 7c9bd9073e6d3c..8ffe3ad042fbaf 100644 --- a/src/libraries/Common/src/System/Threading/Tasks/TaskToAsyncResult.cs +++ b/src/libraries/Common/src/System/Threading/Tasks/TaskToAsyncResult.cs @@ -32,6 +32,8 @@ static class TaskToAsyncResult public static IAsyncResult Begin(Task task, AsyncCallback? callback, object? state) { #if NET + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(task); #else if (task is null) diff --git a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.WASI.xml b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.WASI.xml index 435d0ef7bdfc70..184012c1e4e644 100644 --- a/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.WASI.xml +++ b/src/libraries/System.Private.CoreLib/src/ILLink/ILLink.Descriptors.LibraryBuild.WASI.xml @@ -4,6 +4,7 @@ + diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs index ef2038c86aa84d..285b85485decbf 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Thread.Unix.cs @@ -6,6 +6,7 @@ using System.Runtime.InteropServices; using Microsoft.Win32.SafeHandles; using System.Threading.Tasks; +using System.Collections.Generic; namespace System.Threading { @@ -18,6 +19,11 @@ internal static System.Threading.Tasks.Task RegisterWasiPollableHandle(int handl return WasiEventLoop.RegisterWasiPollableHandle(handle, ownsPollable, cancellationToken); } + internal static void RegisterWasiPollHook(object? state, Func> beforePollHook, Action onResolveCallback, CancellationToken cancellationToken) + { + WasiEventLoop.RegisterWasiPollHook(state, beforePollHook, onResolveCallback, cancellationToken); + } + internal static T PollWasiEventLoopUntilResolved(Task mainTask) { return WasiEventLoop.PollWasiEventLoopUntilResolved(mainTask); diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs index 5034e23dd011d8..371b40ac8b3d84 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs @@ -15,6 +15,7 @@ internal static class WasiEventLoop // it will be leaked and stay in this list forever. // it will also keep the Pollable handle alive and prevent it from being disposed private static readonly List s_pollables = new(); + private static readonly List s_hooks = new(); private static bool s_checkScheduled; private static Pollable? s_resolvedPollable; private static Task? s_mainTask; @@ -38,6 +39,15 @@ internal static Task RegisterWasiPollable(Pollable pollable, bool ownsPollable, return holder.taskCompletionSource.Task; } + internal static void RegisterWasiPollHook(object? state, Func> beforePollHook, Action onResolveCallback, CancellationToken cancellationToken) + { + // this will register the poll hook into s_hooks + var holder = new PollHook(state, beforePollHook, onResolveCallback, cancellationToken); + s_hooks.Add(holder); + + ScheduleCheck(); + } + internal static T PollWasiEventLoopUntilResolved(Task mainTask) { @@ -86,7 +96,7 @@ internal static void PollWasiEventLoopUntilResolvedVoid(Task mainTask) internal static void ScheduleCheck() { - if (!s_checkScheduled && s_pollables.Count > 0) + if (!s_checkScheduled && (s_pollables.Count > 0 || s_hooks.Count > 0)) { s_checkScheduled = true; ThreadPool.UnsafeQueueUserWorkItem(CheckPollables, null); @@ -98,6 +108,7 @@ internal static void CheckPollables(object? _) s_checkScheduled = false; var holders = new List(s_pollables.Count); + var hooks = new List(s_pollables.Count); var pending = new List(s_pollables.Count); for (int i = 0; i < s_pollables.Count; i++) { @@ -108,8 +119,24 @@ internal static void CheckPollables(object? _) pending.Add(holder.pollable); } } + for (int i = 0; i < s_hooks.Count; i++) + { + var hook = s_hooks[i]; + if (!hook.isDisposed) + { + var handles = hook.BeforePollHook(hook.State); + for (int h = 0; h < handles.Count; h++) + { + var handle = handles[h]; + var pollableCpy = new Pollable(new Pollable.THandle(handle)); + hooks.Add(hook); + pending.Add(pollableCpy); + } + } + } s_pollables.Clear(); + s_hooks.Clear(); if (pending.Count > 0) { @@ -124,15 +151,23 @@ internal static void CheckPollables(object? _) pending.Add(s_resolvedPollable); } + // this could block, this is blocking WASI API call var readyIndexes = PollInterop.Poll(pending); + + var holdersCount = holders.Count; for (int i = 0; i < readyIndexes.Length; i++) { uint readyIndex = readyIndexes[i]; - if (resolvedPollableIndex != readyIndex) + if (readyIndex < holdersCount) { var holder = holders[(int)readyIndex]; holder.ResolveAndDispose(); } + else if (resolvedPollableIndex != readyIndex) + { + var hook = hooks[(int)readyIndex-holdersCount]; + hook.Resolve(); + } } for (int i = 0; i < holders.Count; i++) @@ -143,9 +178,18 @@ internal static void CheckPollables(object? _) s_pollables.Add(holder); } } + } - ScheduleCheck(); + for (int i = 0; i < hooks.Count; i++) + { + PollHook hook = hooks[i]; + if (!hook.isDisposed) + { + s_hooks.Add(hook); + } } + + ScheduleCheck(); } private sealed class PollableHolder @@ -205,5 +249,42 @@ public static void CancelAndDispose(object? s) self.taskCompletionSource.TrySetCanceled(self.cancellationToken); } } + + private sealed class PollHook + { + public bool isDisposed; + public readonly object? State; + public readonly Func> BeforePollHook; + public readonly Action OnResolveCallback; + public readonly CancellationTokenRegistration cancellationTokenRegistration; + + public PollHook(object? state, Func> beforePollHook, Action onResolveCallback, CancellationToken cancellationToken) + { + this.State = state; + this.BeforePollHook = beforePollHook; + this.OnResolveCallback = onResolveCallback; + + // static method is used to avoid allocating a delegate + cancellationTokenRegistration = cancellationToken.Register(Dispose, this); + } + + public void Resolve() + { + OnResolveCallback(State); + } + + public static void Dispose(object? s) + { + PollHook self = (PollHook)s!; + if (self.isDisposed) + { + return; + } + + // it will be removed from s_pollables on the next run + self.isDisposed = true; + self.cancellationTokenRegistration.Dispose(); + } + } } } diff --git a/src/mono/sample/wasi/Directory.Build.targets b/src/mono/sample/wasi/Directory.Build.targets index 90f89953129d78..e148ab91a59ced 100644 --- a/src/mono/sample/wasi/Directory.Build.targets +++ b/src/mono/sample/wasi/Directory.Build.targets @@ -39,6 +39,7 @@ $(WasiCommand) --wasi http + $(WasiCommand) --wasi inherit-network --wasi tcp --wasi udp --wasi allow-ip-name-lookup $(WasiCommand) --dir . $(WasiCommand) $(_DotnetWasmName) $(WasiCommand) $(_SampleProjectName) From 90f6801600eba9009d96483ced28f3c4773c49be Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 24 Sep 2024 00:54:35 +0200 Subject: [PATCH 02/14] wasi:sockets implementation --- .../Wasi/System.Native/Interop.SocketEvent.cs | 25 ++ .../Net/SocketProtocolSupportPal.Unix.cs | 2 +- .../System.Net.Sockets/Directory.Build.props | 3 +- .../src/System.Net.Sockets.csproj | 24 +- .../src/System/Net/Sockets/NetworkStream.cs | 30 ++- .../Net/Sockets/SafeSocketHandle.Unix.cs | 5 + .../src/System/Net/Sockets/Socket.Unix.cs | 13 + .../src/System/Net/Sockets/Socket.cs | 170 ++++++++++++- .../Net/Sockets/SocketAsyncContext.Unix.cs | 34 ++- .../Net/Sockets/SocketAsyncContext.Wasi.cs | 19 ++ .../Net/Sockets/SocketAsyncEngine.Unix.cs | 2 +- .../Net/Sockets/SocketAsyncEngine.Wasi.cs | 151 ++++++++++++ .../src/System/Net/Sockets/SocketPal.Unix.cs | 20 +- .../src/System/Net/Sockets/SocketPal.Wasi.cs | 223 ++++++++++++++++++ .../src/System/Net/Sockets/TCPClient.cs | 48 +++- .../src/System/Net/Sockets/TCPListener.cs | 8 +- .../src/System/Net/Sockets/UDPClient.cs | 24 ++ .../Sockets/UnixDomainSocketEndPoint.Wasi.cs | 73 ++++++ src/native/libs/System.Native/entrypoints.c | 1 + .../libs/System.Native/pal_networking.c | 64 ++++- .../libs/System.Native/pal_networking.h | 2 + 21 files changed, 901 insertions(+), 40 deletions(-) create mode 100644 src/libraries/Common/src/Interop/Wasi/System.Native/Interop.SocketEvent.cs create mode 100644 src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Wasi.cs create mode 100644 src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs create mode 100644 src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs create mode 100644 src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Wasi.cs diff --git a/src/libraries/Common/src/Interop/Wasi/System.Native/Interop.SocketEvent.cs b/src/libraries/Common/src/Interop/Wasi/System.Native/Interop.SocketEvent.cs new file mode 100644 index 00000000000000..2e8742bc4c7708 --- /dev/null +++ b/src/libraries/Common/src/Interop/Wasi/System.Native/Interop.SocketEvent.cs @@ -0,0 +1,25 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Runtime.InteropServices; + +internal static partial class Interop +{ + internal static partial class Sys + { + [Flags] + internal enum SocketEvents : int + { + None = 0x00, + Read = 0x01, + Write = 0x02, + ReadClose = 0x04, + Close = 0x08, + Error = 0x10 + } + + [LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetWasiSocketDescriptor")] + internal static unsafe partial Error GetWasiSocketDescriptor(IntPtr socket, IntPtr* entry); + } +} diff --git a/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs b/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs index cb81412f460adb..41cdd601dc5611 100644 --- a/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs +++ b/src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs @@ -14,7 +14,7 @@ private static unsafe bool IsSupported(AddressFamily af) { // Check for AF_UNIX on iOS/tvOS. The OS claims to support this, but returns EPERM on bind. // We should explicitly set the return here to false, to avoid giving a false impression. - if (af == AddressFamily.Unix && (OperatingSystem.IsTvOS() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()))) + if (af == AddressFamily.Unix && (OperatingSystem.IsTvOS() || OperatingSystem.IsWasi() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst()))) { return false; } diff --git a/src/libraries/System.Net.Sockets/Directory.Build.props b/src/libraries/System.Net.Sockets/Directory.Build.props index bc799605d32edf..ce244cbea56199 100644 --- a/src/libraries/System.Net.Sockets/Directory.Build.props +++ b/src/libraries/System.Net.Sockets/Directory.Build.props @@ -3,7 +3,6 @@ Microsoft true - - browser;wasi + browser \ No newline at end of file diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj index e7a4cfbcce3c9f..043fd6ecaba8ce 100644 --- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj +++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj @@ -1,7 +1,7 @@ - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent) + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent) true @@ -48,7 +48,7 @@ - + @@ -183,14 +183,28 @@ Link="Common\System\Net\CompletionPortHelper.Windows.cs" /> + + + + + + + + + + + + + + - - - buffer) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (GetType() != typeof(NetworkStream)) { // NetworkStream is not sealed, and a derived type may have overridden Read(byte[], int, int) prior @@ -260,6 +272,8 @@ public override int Read(Span buffer) public override unsafe int ReadByte() { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + byte b; return Read(new Span(&b, 1)) == 0 ? -1 : b; } @@ -282,6 +296,8 @@ public override unsafe int ReadByte() // way to indicate an error. public override void Write(byte[] buffer, int offset, int count) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ValidateBufferArguments(buffer, offset, count); ThrowIfDisposed(); if (!CanWrite) @@ -303,6 +319,8 @@ public override void Write(byte[] buffer, int offset, int count) public override void Write(ReadOnlySpan buffer) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (GetType() != typeof(NetworkStream)) { // NetworkStream is not sealed, and a derived type may have overridden Write(byte[], int, int) prior @@ -414,6 +432,8 @@ protected override void Dispose(bool disposing) // An IASyncResult, representing the read. public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ValidateBufferArguments(buffer, offset, count); ThrowIfDisposed(); if (!CanRead) @@ -447,6 +467,8 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, Asy // The number of bytes read. May throw an exception. public override int EndRead(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(asyncResult); @@ -476,6 +498,8 @@ public override int EndRead(IAsyncResult asyncResult) // An IASyncResult, representing the write. public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ValidateBufferArguments(buffer, offset, count); ThrowIfDisposed(); if (!CanWrite) @@ -506,6 +530,8 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As // Returns: The number of bytes read. May throw an exception. public override void EndWrite(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(asyncResult); @@ -659,6 +685,8 @@ public override void SetLength(long value) private int _currentWriteTimeout = -1; internal void SetSocketTimeoutOption(SocketShutdown mode, int timeout, bool silent) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 + if (timeout < 0) { timeout = 0; // -1 becomes 0 for the winsock stack diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs index e3d609c69483c9..cb5420dab85036 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs @@ -231,6 +231,11 @@ private unsafe SocketError DoCloseHandle(bool abortive) { return SocketPal.GetSocketErrorForErrorCode(CloseHandle(handle)); } + if (OperatingSystem.IsWasi()) + { + // WASI never blocks and doesn't support linger options + return SocketPal.GetSocketErrorForErrorCode(CloseHandle(handle)); + } // If abortive is not set, we're not running on the finalizer thread, so it's safe to block here. // We can honor the linger options set on the socket. It also means closesocket() might return diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs index 3e4650f547c483..dc5c872e3d8e76 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs @@ -61,6 +61,19 @@ partial void ValidateForMultiConnect(bool isMultiEndpoint) private static unsafe void LoadSocketTypeFromHandle( SafeSocketHandle handle, out AddressFamily addressFamily, out SocketType socketType, out ProtocolType protocolType, out bool blocking, out bool isListening, out bool isSocket) { + if (OperatingSystem.IsWasi()) + { + // Unify with unix after https://github.com/WebAssembly/wasi-libc/issues/537 + blocking = false; + Interop.Error e = Interop.Sys.GetSocketType(handle, out addressFamily, out socketType, out protocolType, out isListening); + if (e == Interop.Error.ENOTSOCK) + { + throw new SocketException((int)SocketError.NotSocket); + } + handle.IsSocket = isSocket = true; + return; + } + if (Interop.Sys.FStat(handle, out Interop.Sys.FileStatus stat) == -1) { throw new SocketException((int)SocketError.NotSocket); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index e1f19c03d6d0ad..98767eccd96f04 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -45,8 +45,8 @@ public partial class Socket : IDisposable // When the socket is created it will be in blocking mode. We'll only be able to Accept or Connect, // so we need to handle one of these cases at a time. - private bool _willBlock = true; // Desired state of the socket from the user. - private bool _willBlockInternal = true; // Actual win32 state of the socket. + private bool _willBlock = !OperatingSystem.IsWasi(); // Desired state of the socket from the user. + private bool _willBlockInternal = !OperatingSystem.IsWasi(); // Actual state of the socket. private bool _isListening; // Our internal state doesn't automatically get updated after a non-blocking connect @@ -72,7 +72,7 @@ public partial class Socket : IDisposable public Socket(SocketType socketType, ProtocolType protocolType) : this(OSSupportsIPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, socketType, protocolType) { - if (OSSupportsIPv6) + if (!OperatingSystem.IsWasi() && OSSupportsIPv6) { DualMode = true; } @@ -169,6 +169,8 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) break; case AddressFamily.Unix: + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + _rightEndPoint = new UnixDomainSocketEndPoint(buffer.Slice(0, bufferLength)); break; } @@ -201,6 +203,8 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) break; case AddressFamily.Unix: + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + _remoteEndPoint = new UnixDomainSocketEndPoint(buffer.Slice(0, bufferLength)); break; } @@ -497,6 +501,7 @@ public bool ExclusiveAddressUse { throw new InvalidOperationException(SR.net_sockets_mustnotbebound); } + if (OperatingSystem.IsWasi() && value) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0); } } @@ -534,10 +539,12 @@ public int ReceiveTimeout { get { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)!; } set { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ArgumentOutOfRangeException.ThrowIfLessThan(value, -1); if (value == -1) { @@ -552,11 +559,13 @@ public int SendTimeout { get { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return (int)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)!; } set { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ArgumentOutOfRangeException.ThrowIfLessThan(value, -1); if (value == -1) { @@ -572,10 +581,14 @@ public LingerOption? LingerState { get { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return (LingerOption?)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger); } set { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, value!); } } @@ -636,6 +649,8 @@ public bool DontFragment { get { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (_addressFamily == AddressFamily.InterNetwork || (_addressFamily == AddressFamily.InterNetworkV6 && DualMode)) { return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment)! != 0 ? true : false; @@ -648,6 +663,8 @@ public bool DontFragment set { + if (OperatingSystem.IsWasi() && value) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (_addressFamily == AddressFamily.InterNetwork || (_addressFamily == AddressFamily.InterNetworkV6 && DualMode)) { SetSocketOption(SocketOptionLevel.IP, SocketOptionName.DontFragment, value ? 1 : 0); @@ -663,6 +680,10 @@ public bool MulticastLoopback { get { + if (OperatingSystem.IsWasi()) + { + return false; + } if (_addressFamily == AddressFamily.InterNetwork) { return (int)GetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback)! != 0 ? true : false; @@ -679,6 +700,7 @@ public bool MulticastLoopback set { + if (OperatingSystem.IsWasi() && value) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 if (_addressFamily == AddressFamily.InterNetwork) { SetSocketOption(SocketOptionLevel.IP, SocketOptionName.MulticastLoopback, value ? 1 : 0); @@ -699,7 +721,7 @@ public bool EnableBroadcast { get { - if (SocketType == SocketType.Stream) + if (OperatingSystem.IsWasi() || SocketType == SocketType.Stream) { return false; } @@ -707,6 +729,7 @@ public bool EnableBroadcast } set { + if (OperatingSystem.IsWasi() && value) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, value ? 1 : 0); } } @@ -723,6 +746,10 @@ public bool DualMode { return false; } + if (OperatingSystem.IsWasi()) + { + return false; + } return ((int)GetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only)! == 0); } set @@ -731,6 +758,9 @@ public bool DualMode { throw new NotSupportedException(SR.net_invalidversion); } + + if (OperatingSystem.IsWasi() && value) throw new PlatformNotSupportedException(); + SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1); } } @@ -796,6 +826,8 @@ private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) // Establishes a connection to a remote system. public void Connect(EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(remoteEP); @@ -840,6 +872,8 @@ public void Connect(EndPoint remoteEP) public void Connect(IPAddress address, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(address); @@ -863,6 +897,8 @@ public void Connect(IPAddress address, int port) public void Connect(string host, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(host); @@ -892,6 +928,8 @@ public void Connect(string host, int port) public void Connect(IPAddress[] addresses, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(addresses); @@ -987,6 +1025,8 @@ public void Listen(int backlog) // Creates a new Sockets.Socket instance to handle an incoming connection. public Socket Accept() { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); if (_rightEndPoint == null) @@ -1054,26 +1094,36 @@ public Socket Accept() // Sends a data buffer to a connected socket. public int Send(byte[] buffer, int size, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Send(buffer, 0, size, socketFlags); } public int Send(byte[] buffer, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Send(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags); } public int Send(byte[] buffer) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Send(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None); } public int Send(IList> buffers) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Send(buffers, SocketFlags.None); } public int Send(IList> buffers, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SocketError errorCode; int bytesTransferred = Send(buffers, socketFlags, out errorCode); if (errorCode != SocketError.Success) @@ -1085,6 +1135,8 @@ public int Send(IList> buffers, SocketFlags socketFlags) public int Send(IList> buffers, SocketFlags socketFlags, out SocketError errorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(buffers); @@ -1121,6 +1173,8 @@ public int Send(IList> buffers, SocketFlags socketFlags, out // Sends data to a connected socket, starting at the indicated location in the buffer. public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SocketError errorCode; int bytesTransferred = Send(buffer, offset, size, socketFlags, out errorCode); if (errorCode != SocketError.Success) @@ -1132,6 +1186,8 @@ public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -1171,6 +1227,8 @@ public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, ou public int Send(ReadOnlySpan buffer, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + int bytesTransferred = Send(buffer, socketFlags, out SocketError errorCode); return errorCode == SocketError.Success ? bytesTransferred : @@ -1179,6 +1237,8 @@ public int Send(ReadOnlySpan buffer, SocketFlags socketFlags) public int Send(ReadOnlySpan buffer, SocketFlags socketFlags, out SocketError errorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBlockingMode(); @@ -1204,6 +1264,8 @@ public int Send(ReadOnlySpan buffer, SocketFlags socketFlags, out SocketEr public void SendFile(string? fileName) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SendFile(fileName, ReadOnlySpan.Empty, ReadOnlySpan.Empty, TransmitFileOptions.UseDefaultWorkerThread); } @@ -1230,6 +1292,8 @@ public void SendFile(string? fileName) /// An error occurred when attempting to access the socket. public void SendFile(string? fileName, byte[]? preBuffer, byte[]? postBuffer, TransmitFileOptions flags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SendFile(fileName, preBuffer.AsSpan(), postBuffer.AsSpan(), flags); } @@ -1256,6 +1320,8 @@ public void SendFile(string? fileName, byte[]? preBuffer, byte[]? postBuffer, Tr /// An error occurred when attempting to access the socket. public void SendFile(string? fileName, ReadOnlySpan preBuffer, ReadOnlySpan postBuffer, TransmitFileOptions flags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); if (!IsConnectionOriented || !Connected) @@ -1273,6 +1339,8 @@ public void SendFile(string? fileName, ReadOnlySpan preBuffer, ReadOnlySpa // Sends data to a specific end point, starting at the indicated location in the buffer. public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -1309,16 +1377,22 @@ public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, // Sends data to a specific end point, starting at the indicated location in the data. public int SendTo(byte[] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return SendTo(buffer, 0, size, socketFlags, remoteEP); } public int SendTo(byte[] buffer, SocketFlags socketFlags, EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return SendTo(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags, remoteEP); } public int SendTo(byte[] buffer, EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return SendTo(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None, remoteEP); } @@ -1333,6 +1407,8 @@ public int SendTo(byte[] buffer, EndPoint remoteEP) /// The has been closed. public int SendTo(ReadOnlySpan buffer, EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return SendTo(buffer, SocketFlags.None, remoteEP); } @@ -1348,6 +1424,8 @@ public int SendTo(ReadOnlySpan buffer, EndPoint remoteEP) /// The has been closed. public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(remoteEP); @@ -1389,6 +1467,8 @@ public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, EndPoint r /// The has been closed. public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, SocketAddress socketAddress) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(socketAddress); @@ -1416,22 +1496,30 @@ public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, SocketAddr // Receives data from a connected socket. public int Receive(byte[] buffer, int size, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Receive(buffer, 0, size, socketFlags); } public int Receive(byte[] buffer, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Receive(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags); } public int Receive(byte[] buffer) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Receive(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None); } // Receives data from a connected socket into a specific location of the receive buffer. public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SocketError errorCode; int bytesTransferred = Receive(buffer, offset, size, socketFlags, out errorCode); if (errorCode != SocketError.Success) @@ -1443,6 +1531,8 @@ public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); ValidateBlockingMode(); @@ -1475,6 +1565,8 @@ public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags, public int Receive(Span buffer, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + int bytesTransferred = Receive(buffer, socketFlags, out SocketError errorCode); return errorCode == SocketError.Success ? bytesTransferred : @@ -1483,6 +1575,8 @@ public int Receive(Span buffer, SocketFlags socketFlags) public int Receive(Span buffer, SocketFlags socketFlags, out SocketError errorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBlockingMode(); @@ -1508,11 +1602,15 @@ public int Receive(Span buffer, SocketFlags socketFlags, out SocketError e public int Receive(IList> buffers) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return Receive(buffers, SocketFlags.None); } public int Receive(IList> buffers, SocketFlags socketFlags) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SocketError errorCode; int bytesTransferred = Receive(buffers, socketFlags, out errorCode); if (errorCode != SocketError.Success) @@ -1524,6 +1622,8 @@ public int Receive(IList> buffers, SocketFlags socketFlags) public int Receive(IList> buffers, SocketFlags socketFlags, out SocketError errorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(buffers); @@ -1561,6 +1661,8 @@ public int Receive(IList> buffers, SocketFlags socketFlags, o // the end point. public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP)); @@ -1638,6 +1740,8 @@ public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFla /// You must call the Bind method before performing this operation. public int ReceiveMessageFrom(Span buffer, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(remoteEP); @@ -1698,6 +1802,8 @@ public int ReceiveMessageFrom(Span buffer, ref SocketFlags socketFlags, re // the end point. public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP)); @@ -1777,16 +1883,22 @@ public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFl // Receives a datagram and stores the source end point. public int ReceiveFrom(byte[] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return ReceiveFrom(buffer, 0, size, socketFlags, ref remoteEP); } public int ReceiveFrom(byte[] buffer, SocketFlags socketFlags, ref EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return ReceiveFrom(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags, ref remoteEP); } public int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return ReceiveFrom(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None, ref remoteEP); } @@ -1816,6 +1928,8 @@ public int ReceiveFrom(Span buffer, ref EndPoint remoteEP) /// The has been closed. public int ReceiveFrom(Span buffer, SocketFlags socketFlags, ref EndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP)); @@ -1897,6 +2011,8 @@ public int ReceiveFrom(Span buffer, SocketFlags socketFlags, ref EndPoint /// The has been closed. public int ReceiveFrom(Span buffer, SocketFlags socketFlags, SocketAddress receivedAddress) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(receivedAddress, nameof(receivedAddress)); @@ -2223,6 +2339,8 @@ public void SetIPProtectionLevel(IPProtectionLevel level) /// The has been closed. public bool Poll(int microSeconds, SelectMode mode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); bool status; @@ -2268,6 +2386,8 @@ public bool Poll(TimeSpan timeout, SelectMode mode) => /// One or more sockets was disposed. public static void Select(IList? checkRead, IList? checkWrite, IList? checkError, int microSeconds) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if ((checkRead == null || checkRead.Count == 0) && (checkWrite == null || checkWrite.Count == 0) && (checkError == null || checkError.Count == 0)) @@ -2366,6 +2486,8 @@ public void Disconnect(bool reuseSocket) public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2374,6 +2496,8 @@ public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags s public IAsyncResult? BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2390,6 +2514,8 @@ public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags s public IAsyncResult BeginSend(IList> buffers, SocketFlags socketFlags, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); return TaskToAsyncResult.Begin(SendAsync(buffers, socketFlags), callback, state); @@ -2397,6 +2523,8 @@ public IAsyncResult BeginSend(IList> buffers, SocketFlags soc public IAsyncResult? BeginSend(IList> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); Task t = SendAsync(buffers, socketFlags); @@ -2417,11 +2545,15 @@ public int EndSend(IAsyncResult asyncResult, out SocketError errorCode) => public IAsyncResult BeginSendFile(string? fileName, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + return BeginSendFile(fileName, null, null, TransmitFileOptions.UseDefaultWorkerThread, callback, state); } public IAsyncResult BeginSendFile(string? fileName, byte[]? preBuffer, byte[]? postBuffer, TransmitFileOptions flags, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); if (!Connected) @@ -2438,6 +2570,8 @@ public IAsyncResult BeginSendFile(string? fileName, byte[]? preBuffer, byte[]? p public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); ArgumentNullException.ThrowIfNull(remoteEP); @@ -2450,6 +2584,8 @@ public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); return TaskToAsyncResult.Begin(ReceiveAsync(new ArraySegment(buffer, offset, size), socketFlags, fromNetworkStream: false, default).AsTask(), callback, state); @@ -2457,6 +2593,8 @@ public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlag public IAsyncResult? BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); Task t = ReceiveAsync(new ArraySegment(buffer, offset, size), socketFlags, fromNetworkStream: false, default).AsTask(); @@ -2473,12 +2611,16 @@ public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlag public IAsyncResult BeginReceive(IList> buffers, SocketFlags socketFlags, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); return TaskToAsyncResult.Begin(ReceiveAsync(buffers, socketFlags), callback, state); } public IAsyncResult? BeginReceive(IList> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); Task t = ReceiveAsync(buffers, socketFlags); @@ -2499,6 +2641,8 @@ public int EndReceive(IAsyncResult asyncResult, out SocketError errorCode) => private static int EndSendReceive(IAsyncResult asyncResult, out SocketError errorCode) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + Task ti = TaskToAsyncResult.Unwrap(asyncResult); ((Task)ti).ConfigureAwait(ConfigureAwaitOptions.SuppressThrowing).GetAwaiter().GetResult(); @@ -2515,6 +2659,8 @@ private static int EndSendReceive(IAsyncResult asyncResult, out SocketError erro public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"size:{size}"); ThrowIfDisposed(); @@ -2536,6 +2682,8 @@ public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size, public int EndReceiveMessageFrom(IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(endPoint); if (!CanTryAddressFamily(endPoint.AddressFamily)) { @@ -2554,6 +2702,8 @@ public int EndReceiveMessageFrom(IAsyncResult asyncResult, ref SocketFlags socke public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback? callback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP)); @@ -2572,6 +2722,8 @@ public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, Socket public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ArgumentNullException.ThrowIfNull(endPoint); if (!CanTryAddressFamily(endPoint.AddressFamily)) { @@ -2632,6 +2784,8 @@ public IAsyncResult BeginAccept(Socket? acceptSocket, int receiveSize, AsyncCall public Socket EndAccept(out byte[] buffer, IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + Socket socket = EndAccept(out byte[] innerBuffer, out int bytesTransferred, asyncResult); buffer = new byte[bytesTransferred]; Buffer.BlockCopy(innerBuffer, 0, buffer, 0, bytesTransferred); @@ -2640,6 +2794,8 @@ public Socket EndAccept(out byte[] buffer, IAsyncResult asyncResult) public Socket EndAccept(out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + Socket s; (s, buffer, bytesTransferred) = TaskToAsyncResult.End<(Socket, byte[], int)>(asyncResult); return s; @@ -3010,7 +3166,7 @@ private bool ReceiveMessageFromAsync(SocketAsyncEventArgs e, CancellationToken c // e.m_SocketAddres for Create to work later. e.RemoteEndPoint = endPointSnapshot; - SetReceivingPacketInformation(); + if (!OperatingSystem.IsWasi()) SetReceivingPacketInformation(); // Prepare for and make the native call. e.StartOperationCommon(this, SocketAsyncOperation.ReceiveMessageFrom); @@ -3498,6 +3654,8 @@ private void SetIPv6MulticastOption(SocketOptionName optionName, IPv6MulticastOp private void SetLingerOption(LingerOption lref) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + SocketError errorCode = SocketPal.SetLingerOption(_handle, lref); if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"SetLingerOption returns errorCode:{errorCode}"); @@ -3511,6 +3669,8 @@ private void SetLingerOption(LingerOption lref) private LingerOption? GetLingerOpt() { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + LingerOption? lingerOption; SocketError errorCode = SocketPal.GetLingerOption(_handle, out lingerOption); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs index d5613dc91f481a..7bdc2ff0e90492 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs @@ -30,7 +30,7 @@ namespace System.Net.Sockets // See comments on OperationQueue below for more details of how the queue coordination works. - internal sealed class SocketAsyncContext + internal sealed partial class SocketAsyncContext { // Cached operation instances for operations commonly repeated on the same socket instance, // e.g. async accepts, sends/receives with single and multiple buffers. More can be @@ -1256,12 +1256,12 @@ public void Trace(SocketAsyncContext context, string message, [CallerMemberName] } } - private readonly SafeSocketHandle _socket; + internal readonly SafeSocketHandle _socket; private OperationQueue _receiveQueue; private OperationQueue _sendQueue; private SocketAsyncEngine? _asyncEngine; private bool IsRegistered => _asyncEngine != null; - private bool _isHandleNonBlocking; + private bool _isHandleNonBlocking = OperatingSystem.IsWasi(); // WASI sockets are always non-blocking, because we don't have another thread which could be blocked private readonly object _registerLock = new object(); @@ -1330,13 +1330,18 @@ public bool StopAndAbort() // We don't need to synchronize with Register. // This method is called when the handle gets released. // The Register method will throw ODE when it tries to use the handle at this point. - _asyncEngine?.UnregisterSocket(_socket.DangerousGetHandle()); + _asyncEngine?.UnregisterSocket(_socket.DangerousGetHandle(), this); return aborted; } public void SetHandleNonBlocking() { + if (OperatingSystem.IsWasi()) + { + // WASI sockets are always non-blocking, because in ST we don't have another thread which could be blocked + return; + } // // Our sockets may start as blocking, and later transition to non-blocking, either because the user // explicitly requested non-blocking mode, or because we need non-blocking mode to support async @@ -1362,6 +1367,7 @@ public void SetHandleNonBlocking() private void PerformSyncOperation(ref OperationQueue queue, TOperation operation, int timeout, int observedSequenceNumber) where TOperation : AsyncOperation { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); using (var e = new ManualResetEventSlim(false, 0)) @@ -1498,6 +1504,8 @@ public SocketError AcceptAsync(Memory socketAddress, out int socketAddress public SocketError Connect(Memory socketAddress) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(socketAddress.Length > 0, $"Unexpected socketAddressLen: {socketAddress.Length}"); // Connect is different than the usual "readiness" pattern of other operations. // We need to call TryStartConnect to initiate the connect with the OS, @@ -1590,6 +1598,8 @@ public SocketError ReceiveAsync(Memory buffer, SocketFlags flags, out int public unsafe SocketError ReceiveFrom(Memory buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, int timeout, out int bytesReceived) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); SocketFlags receivedFlags; @@ -1621,6 +1631,8 @@ public unsafe SocketError ReceiveFrom(Memory buffer, ref SocketFlags flags public unsafe SocketError ReceiveFrom(Span buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, int timeout, out int bytesReceived) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + SocketFlags receivedFlags; SocketError errorCode; int observedSequenceNumber; @@ -1731,6 +1743,8 @@ public SocketError ReceiveAsync(IList> buffers, SocketFlags f public unsafe SocketError ReceiveFrom(IList> buffers, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, int timeout, out int bytesReceived) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); SocketFlags receivedFlags; @@ -1798,6 +1812,8 @@ public SocketError ReceiveFromAsync(IList> buffers, SocketFla public SocketError ReceiveMessageFrom( Memory buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, bool isIPv4, bool isIPv6, int timeout, out IPPacketInformation ipPacketInformation, out int bytesReceived) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); SocketFlags receivedFlags; @@ -1833,6 +1849,8 @@ public SocketError ReceiveMessageFrom( public unsafe SocketError ReceiveMessageFrom( Span buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, bool isIPv4, bool isIPv6, int timeout, out IPPacketInformation ipPacketInformation, out int bytesReceived) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); SocketFlags receivedFlags; @@ -1923,6 +1941,8 @@ public SocketError SendAsync(Memory buffer, int offset, int count, SocketF public SocketError SendTo(byte[] buffer, int offset, int count, SocketFlags flags, Memory socketAddress, int timeout, out int bytesSent) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); bytesSent = 0; @@ -1953,6 +1973,8 @@ public SocketError SendTo(byte[] buffer, int offset, int count, SocketFlags flag public unsafe SocketError SendTo(ReadOnlySpan buffer, SocketFlags flags, Memory socketAddress, int timeout, out int bytesSent) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); bytesSent = 0; @@ -2030,6 +2052,8 @@ public SocketError SendAsync(IList> buffers, SocketFlags flag public SocketError SendTo(IList> buffers, SocketFlags flags, Memory socketAddress, int timeout, out int bytesSent) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); bytesSent = 0; @@ -2098,6 +2122,8 @@ public SocketError SendToAsync(IList> buffers, SocketFlags fl public SocketError SendFile(SafeFileHandle fileHandle, long offset, long count, int timeout, out long bytesSent) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); bytesSent = 0; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Wasi.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Wasi.cs new file mode 100644 index 00000000000000..fbe89b6fa64c00 --- /dev/null +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Wasi.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Generic; +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using Microsoft.Win32.SafeHandles; +using System.Runtime.Versioning; + +namespace System.Net.Sockets +{ + internal sealed partial class SocketAsyncContext + { + public CancellationTokenSource unregisterPollHook = new(); + } +} diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs index 43364203118470..7405e579042232 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Unix.cs @@ -138,7 +138,7 @@ private bool TryRegisterCore(IntPtr socketHandle, SocketAsyncContext context, ou return false; } - public void UnregisterSocket(IntPtr socketHandle) + public void UnregisterSocket(IntPtr socketHandle, SocketAsyncContext __) { _handleToContextMap.TryRemove(socketHandle, out _); } diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs new file mode 100644 index 00000000000000..3eeffd491835e8 --- /dev/null +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections.Concurrent; +using System.Collections.Generic; +using System.Diagnostics; +using System.Net.Sockets; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using static Interop; +using static Interop.Sys; + +namespace System.Net.Sockets +{ + internal sealed unsafe class SocketAsyncEngine + { + internal static readonly bool InlineSocketCompletionsEnabled = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS") == "1"; + internal static readonly TaskContinuationOptions ContinuationOptions = InlineSocketCompletionsEnabled ? TaskContinuationOptions.ExecuteSynchronously : TaskContinuationOptions.RunContinuationsAsynchronously; + private static readonly SocketAsyncEngine s_engine = new SocketAsyncEngine(); + + public static bool TryRegisterSocket(IntPtr socketHandle, SocketAsyncContext context, out SocketAsyncEngine? engine, out Interop.Error error) + { + engine = s_engine; + + nint entryPtr = default; + error = Interop.Sys.GetWasiSocketDescriptor(socketHandle, &entryPtr); + if (error != Interop.Error.SUCCESS) + { + return false; + } + + RegisterWasiPollHook(context, BeforePollHook, HandleSocketEvent, context.unregisterPollHook.Token); + + return true; + } + +#pragma warning disable CA1822 + public void UnregisterSocket(IntPtr _, SocketAsyncContext context) +#pragma warning restore CA1822 + { + context.unregisterPollHook.Cancel(); + } + + public static IList BeforePollHook(object? state) + { + var context = (SocketAsyncContext)state!; + if (context._socket.IsClosed) + { + return []; + } + + List pollableHandles = new(); + // fail fast if the handle is not found in the descriptor table + // probably because the socket was closed and the entry was removed, without unregistering the poll hook + nint entryPtr = default; + IntPtr socketHandle = context._socket.DangerousGetHandle(); + var error = Interop.Sys.GetWasiSocketDescriptor(socketHandle, &entryPtr); + if (error != Interop.Error.SUCCESS) + { + Environment.FailFast("Can't resolve libc descriptor for socket handle " + socketHandle); + } + + var entry = (descriptor_table_entry_t*)entryPtr; + switch (entry->tag) + { + case descriptor_table_entry_tag.DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET: + { + tcp_socket_t* socket = &(entry->entry.tcp_socket); + switch (socket->state.tag) + { + case tcp_socket_state_tag.TCP_SOCKET_STATE_CONNECTING: + case tcp_socket_state_tag.TCP_SOCKET_STATE_LISTENING: + pollableHandles.Add(socket->socket_pollable.handle); + break; + case tcp_socket_state_tag.TCP_SOCKET_STATE_CONNECTED: + pollableHandles.Add(socket->state.state.connected.input_pollable.handle); + pollableHandles.Add(socket->state.state.connected.output_pollable.handle); + break; + case tcp_socket_state_tag.TCP_SOCKET_STATE_CONNECT_FAILED: + context.HandleEventsInline(Sys.SocketEvents.Error); + break; + case tcp_socket_state_tag.TCP_SOCKET_STATE_UNBOUND: + case tcp_socket_state_tag.TCP_SOCKET_STATE_BOUND: + break; + default: + throw new NotImplementedException("TCP:" + socket->state.tag); + } + break; + } + case descriptor_table_entry_tag.DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET: + { + udp_socket_t* socket = &(entry->entry.udp_socket); + switch (socket->state.tag) + { + case udp_socket_state_tag.UDP_SOCKET_STATE_UNBOUND: + case udp_socket_state_tag.UDP_SOCKET_STATE_BOUND_NOSTREAMS: + // TODO ? pollableHandles.Add(socket->socket_pollable.handle); + context.HandleEventsInline(Sys.SocketEvents.Read | Sys.SocketEvents.Write); + break; + case udp_socket_state_tag.UDP_SOCKET_STATE_BOUND_STREAMING: + case udp_socket_state_tag.UDP_SOCKET_STATE_CONNECTED: + { + udp_socket_streams_t* streams; + if (socket->state.tag == udp_socket_state_tag.UDP_SOCKET_STATE_BOUND_STREAMING) + { + streams = &(socket->state.state.bound_streaming.streams); + } + else + { + streams = &(socket->state.state.connected.streams); + } + pollableHandles.Add(streams->incoming_pollable.handle); + pollableHandles.Add(streams->outgoing_pollable.handle); + break; + } + + default: + throw new NotImplementedException("UDP" + socket->state.tag); + } + break; + } + default: + throw new NotImplementedException("TYPE" + entry->tag); + } + return pollableHandles; + } + + public static void HandleSocketEvent(object? state) + { + SocketAsyncContext ctx = (SocketAsyncContext)state!; + try + { + ctx.HandleEventsInline(Sys.SocketEvents.Write | Sys.SocketEvents.Read); + } + catch (Exception e) + { + Environment.FailFast("Exception thrown from SocketAsyncEngine event loop: " + e.ToString(), e); + } + } + + private static void RegisterWasiPollHook(object? state, Func> beforePollHook, Action onResolveCallback, CancellationToken cancellationToken) + { + CallRegisterWasiPollHook((Thread)null!, state, beforePollHook, onResolveCallback, cancellationToken); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "RegisterWasiPollHook")] + static extern void CallRegisterWasiPollHook(Thread t, object? state, Func> beforePollHook, Action onResolveCallback, CancellationToken cancellationToken); + } + } +} diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs index 579c2dea66160c..8e7882eb2cb52a 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs @@ -71,7 +71,7 @@ public static unsafe SocketError CreateSocket(AddressFamily addressFamily, Socke // The socket was created successfully; enable IPV6_V6ONLY by default for normal AF_INET6 sockets. // This fails on raw sockets so we just let them be in default state. - if (addressFamily == AddressFamily.InterNetworkV6 && socketType != SocketType.Raw) + if (!OperatingSystem.IsWasi() && addressFamily == AddressFamily.InterNetworkV6 && socketType != SocketType.Raw) { int on = 1; error = Interop.Sys.SetSockOpt(fd, SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, (byte*)&on, sizeof(int)); @@ -289,6 +289,11 @@ private static unsafe int SysSend(SafeSocketHandle socket, SocketFlags flags, IL int startIndex = bufferIndex, startOffset = offset; int maxBuffers = buffers.Count - startIndex; + if (OperatingSystem.IsWasi()) + { + // WASI doesn't have iovecs and recvmsg in preview2 + maxBuffers = Math.Max(maxBuffers, 1); + } bool allocOnStack = maxBuffers <= IovStackThreshold; Span handles = allocOnStack ? stackalloc GCHandle[IovStackThreshold] : new GCHandle[maxBuffers]; Span iovecs = allocOnStack ? stackalloc Interop.Sys.IOVector[IovStackThreshold] : new Interop.Sys.IOVector[maxBuffers]; @@ -376,6 +381,11 @@ private static unsafe int SysReceive(SafeSocketHandle socket, SocketFlags flags, Debug.Assert(socket.IsSocket); int maxBuffers = buffers.Count; + if (OperatingSystem.IsWasi()) + { + // WASI doesn't have iovecs and recvmsg in preview2 + maxBuffers = Math.Max(maxBuffers, 1); + } bool allocOnStack = maxBuffers <= IovStackThreshold; // When there are many buffers, reduce the number of pinned buffers based on available bytes. @@ -532,6 +542,12 @@ private static unsafe int SysReceiveMessageFrom( Debug.Assert(socket.IsSocket); int buffersCount = buffers.Count; + if (OperatingSystem.IsWasi()) + { + // WASI doesn't have iovecs and sendmsg in preview2 + buffersCount = Math.Max(buffersCount, 1); + } + bool allocOnStack = buffersCount <= IovStackThreshold; Span handles = allocOnStack ? stackalloc GCHandle[IovStackThreshold] : new GCHandle[buffersCount]; Span iovecs = allocOnStack ? stackalloc Interop.Sys.IOVector[IovStackThreshold] : new Interop.Sys.IOVector[buffersCount]; @@ -1056,6 +1072,8 @@ public static bool TryCompleteSendFile(SafeSocketHandle socket, SafeFileHandle h public static SocketError SetBlocking(SafeSocketHandle handle, bool shouldBlock, out bool willBlock) { + if(OperatingSystem.IsWasi() && shouldBlock) throw new PlatformNotSupportedException(); + handle.IsNonBlocking = !shouldBlock; willBlock = shouldBlock; return SocketError.Success; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs new file mode 100644 index 00000000000000..439270e2bb6527 --- /dev/null +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs @@ -0,0 +1,223 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.Win32.SafeHandles; + +namespace System.Net.Sockets +{ + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_own_tcp_socket_t + { + public int handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_own_udp_socket_t + { + public int handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_own_incoming_datagram_stream_t + { + public int handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_own_outgoing_datagram_stream_t + { + public int handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct streams_own_input_stream_t + { + public int handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct poll_own_pollable_t + { + public int handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct streams_own_output_stream_t + { + public int handle; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_state_unbound_t + { + public int dummy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_state_bound_t + { + public int dummy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_state_connecting_t + { + public int dummy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_state_listening_t + { + public int dummy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_state_connected_t + { + public streams_own_input_stream_t input; + public poll_own_pollable_t input_pollable; + public streams_own_output_stream_t output; + public poll_own_pollable_t output_pollable; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_state_connect_failed_t + { + public byte error_code; + } + + internal enum tcp_socket_state_tag + { + TCP_SOCKET_STATE_UNBOUND, + TCP_SOCKET_STATE_BOUND, + TCP_SOCKET_STATE_CONNECTING, + TCP_SOCKET_STATE_CONNECTED, + TCP_SOCKET_STATE_CONNECT_FAILED, + TCP_SOCKET_STATE_LISTENING, + } + + [StructLayout(LayoutKind.Explicit)] + internal struct tcp_socket_state_union + { + [FieldOffset(0)] public tcp_socket_state_unbound_t unbound; + [FieldOffset(0)] public tcp_socket_state_bound_t bound; + [FieldOffset(0)] public tcp_socket_state_connecting_t connecting; + [FieldOffset(0)] public tcp_socket_state_connected_t connected; + [FieldOffset(0)] public tcp_socket_state_connect_failed_t connect_failed; + [FieldOffset(0)] public tcp_socket_state_listening_t listening; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_state_t + { + public tcp_socket_state_tag tag; + public tcp_socket_state_union state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct tcp_socket_t + { + public tcp_own_tcp_socket_t socket; + public poll_own_pollable_t socket_pollable; + public bool blocking; + public bool fake_nodelay; + public bool fake_reuseaddr; + public byte family; + public tcp_socket_state_t state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_socket_streams_t + { + public udp_own_incoming_datagram_stream_t incoming; + public poll_own_pollable_t incoming_pollable; + public udp_own_outgoing_datagram_stream_t outgoing; + public poll_own_pollable_t outgoing_pollable; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_socket_state_unbound_t + { + public int dummy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_socket_state_bound_nostreams_t + { + public int dummy; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_socket_state_bound_streaming_t + { + public udp_socket_streams_t streams; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_socket_state_connected_t + { + public udp_socket_streams_t streams; + } + + internal enum udp_socket_state_tag + { + UDP_SOCKET_STATE_UNBOUND, + UDP_SOCKET_STATE_BOUND_NOSTREAMS, + UDP_SOCKET_STATE_BOUND_STREAMING, + UDP_SOCKET_STATE_CONNECTED, + } + + [StructLayout(LayoutKind.Explicit)] + internal struct udp_socket_state_union + { + [FieldOffset(0)] public udp_socket_state_unbound_t unbound; + [FieldOffset(0)] public udp_socket_state_bound_nostreams_t bound_nostreams; + [FieldOffset(0)] public udp_socket_state_bound_streaming_t bound_streaming; + [FieldOffset(0)] public udp_socket_state_connected_t connected; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_socket_state_t + { + public udp_socket_state_tag tag; + public udp_socket_state_union state; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct udp_socket_t + { + public udp_own_udp_socket_t socket; + public poll_own_pollable_t socket_pollable; + public bool blocking; + public byte family; + public udp_socket_state_t state; + } + + internal enum descriptor_table_entry_tag + { + DESCRIPTOR_TABLE_ENTRY_TCP_SOCKET, + DESCRIPTOR_TABLE_ENTRY_UDP_SOCKET, + } + + [StructLayout(LayoutKind.Explicit)] + internal struct descriptor_table_entry_union + { + [FieldOffset(0)] public tcp_socket_t tcp_socket; + [FieldOffset(0)] public udp_socket_t udp_socket; + } + + [StructLayout(LayoutKind.Sequential)] + internal struct descriptor_table_entry_t + { + public descriptor_table_entry_tag tag; + public descriptor_table_entry_union entry; + } +} diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs index 54998d3e02e93e..0a64e420e47982 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs @@ -123,6 +123,8 @@ public bool ExclusiveAddressUse // Connects the Client to the specified port on the specified host. public void Connect(string hostname, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(hostname); @@ -140,6 +142,8 @@ public void Connect(string hostname, int port) // Connects the Client to the specified port on the specified host. public void Connect(IPAddress address, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(address); @@ -155,6 +159,8 @@ public void Connect(IPAddress address, int port) // Connect the Client to the specified end point. public void Connect(IPEndPoint remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(remoteEP); @@ -166,6 +172,10 @@ public void Connect(IPEndPoint remoteEP) public void Connect(IPAddress[] ipAddresses, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + + ThrowIfDisposed(); + Client.Connect(ipAddresses, port); _family = Client.AddressFamily; _active = true; @@ -229,6 +239,8 @@ public IAsyncResult BeginConnect(IPAddress[] addresses, int port, AsyncCallback? public void EndConnect(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + _clientSocket.EndConnect(asyncResult); _active = true; @@ -307,23 +319,47 @@ public int SendBufferSize // Gets or sets the receive time out value of the connection in milliseconds. public int ReceiveTimeout { - get { return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)!; } - set { Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value); } + get + { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 + return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)!; + } + set + { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 + Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, value); + } } // Gets or sets the send time out value of the connection in milliseconds. public int SendTimeout { - get { return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)!; } - set { Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value); } + get + { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 + return (int)Client.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)!; + } + set + { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 + Client.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, value); + } } // Gets or sets the value of the connection's linger option. [DisallowNull] public LingerOption? LingerState { - get { return Client.LingerState; } - set { Client.LingerState = value!; } + get + { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 + return Client.LingerState; + } + set + { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 + Client.LingerState = value!; + } } // Enables or disables delay when send or receive buffers are full. diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs index 06f80e97a52f5f..661a4fe95be4f0 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs @@ -191,6 +191,8 @@ public Socket AcceptSocket() throw new InvalidOperationException(SR.net_stopped); } + if (OperatingSystem.IsWasi() && _serverSocket!.Blocking) throw new PlatformNotSupportedException("Only use with Socket.Blocking=false on WASI"); + return _serverSocket!.Accept(); } @@ -201,6 +203,8 @@ public TcpClient AcceptTcpClient() throw new InvalidOperationException(SR.net_stopped); } + if (OperatingSystem.IsWasi() && _serverSocket!.Blocking) throw new PlatformNotSupportedException("Only use with Socket.Blocking=false on WASI"); + Socket acceptedSocket = _serverSocket!.Accept(); return new TcpClient(acceptedSocket); } @@ -252,7 +256,7 @@ public static TcpListener Create(int port) { // If OS supports IPv6 use dual mode so both address families work. listener = new TcpListener(IPAddress.IPv6Any, port); - listener.Server.DualMode = true; + if (!OperatingSystem.IsWasi()) listener.Server.DualMode = true; } else { @@ -286,6 +290,8 @@ private void CreateNewSocketIfNeeded() private TResult EndAcceptCore(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + try { return TaskToAsyncResult.End(asyncResult); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs index 8d628720d7e43a..dc05ee34345ad0 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs @@ -284,6 +284,8 @@ public IAsyncResult BeginSend(byte[] datagram, int bytes, string? hostname, int public IAsyncResult BeginSend(byte[] datagram, int bytes, IPEndPoint? endPoint, AsyncCallback? requestCallback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ValidateDatagram(datagram, bytes, endPoint); if (endPoint is null) @@ -299,6 +301,8 @@ public IAsyncResult BeginSend(byte[] datagram, int bytes, IPEndPoint? endPoint, public int EndSend(IAsyncResult asyncResult) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); return _active ? @@ -354,6 +358,8 @@ private void ValidateDatagram(byte[] datagram, int bytes, IPEndPoint? endPoint) public IAsyncResult BeginReceive(AsyncCallback? requestCallback, object? state) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); // Due to the nature of the ReceiveFrom() call and the ref parameter convention, @@ -368,6 +374,8 @@ public IAsyncResult BeginReceive(AsyncCallback? requestCallback, object? state) public byte[] EndReceive(IAsyncResult asyncResult, ref IPEndPoint? remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); EndPoint tempRemoteEP = _family == AddressFamily.InterNetwork ? @@ -677,6 +685,8 @@ public void Close() public void Connect(string hostname, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(hostname); @@ -790,6 +800,8 @@ public void Connect(string hostname, int port) public void Connect(IPAddress addr, int port) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(addr); @@ -805,6 +817,8 @@ public void Connect(IPAddress addr, int port) public void Connect(IPEndPoint endPoint) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(endPoint); @@ -816,6 +830,8 @@ public void Connect(IPEndPoint endPoint) public byte[] Receive([NotNull] ref IPEndPoint? remoteEP) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); // this is a fix due to the nature of the ReceiveFrom() call and the @@ -837,6 +853,8 @@ public byte[] Receive([NotNull] ref IPEndPoint? remoteEP) // Sends a UDP datagram to the host at the remote end point. public int Send(byte[] dgram, int bytes, IPEndPoint? endPoint) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(dgram); @@ -871,6 +889,8 @@ public int Send(byte[] dgram, int bytes, IPEndPoint? endPoint) /// An error occurred when accessing the socket. public int Send(ReadOnlySpan datagram, IPEndPoint? endPoint) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); if (_active && endPoint != null) @@ -913,6 +933,8 @@ public int Send(ReadOnlySpan datagram, IPEndPoint? endPoint) // Sends a UDP datagram to a remote host. public int Send(byte[] dgram, int bytes) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(dgram); @@ -937,6 +959,8 @@ public int Send(byte[] dgram, int bytes) /// An error occurred when accessing the socket. public int Send(ReadOnlySpan datagram) { + if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + ThrowIfDisposed(); if (!_active) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Wasi.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Wasi.cs new file mode 100644 index 00000000000000..e2bff511837a3b --- /dev/null +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UnixDomainSocketEndPoint.Wasi.cs @@ -0,0 +1,73 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System.Diagnostics; +using System.Text; + +namespace System.Net.Sockets +{ +#pragma warning disable CA1822 + public sealed partial class UnixDomainSocketEndPoint : System.Net.EndPoint + { + public UnixDomainSocketEndPoint(string path) + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + internal UnixDomainSocketEndPoint(ReadOnlySpan socketAddress) + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + internal string? BoundFileName + { + get + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + } + + public override System.Net.Sockets.AddressFamily AddressFamily + { + get + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + } + + public override System.Net.EndPoint Create(System.Net.SocketAddress socketAddress) + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + public override bool Equals([System.Diagnostics.CodeAnalysis.NotNullWhenAttribute(true)] object? obj) + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + public override int GetHashCode() + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + public override System.Net.SocketAddress Serialize() + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + public override string ToString() + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + internal UnixDomainSocketEndPoint CreateBoundEndPoint() + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + + internal UnixDomainSocketEndPoint CreateUnboundEndPoint() + { + throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + } + } +} diff --git a/src/native/libs/System.Native/entrypoints.c b/src/native/libs/System.Native/entrypoints.c index 2165430d65f56a..fcde21046a7c4b 100644 --- a/src/native/libs/System.Native/entrypoints.c +++ b/src/native/libs/System.Native/entrypoints.c @@ -187,6 +187,7 @@ static const Entry s_sysNative[] = DllImportEntry(SystemNative_FreeSocketEventBuffer) DllImportEntry(SystemNative_TryChangeSocketEventRegistration) DllImportEntry(SystemNative_WaitForSocketEvents) + DllImportEntry(SystemNative_GetWasiSocketDescriptor) DllImportEntry(SystemNative_PlatformSupportsDualModeIPv4PacketInfo) DllImportEntry(SystemNative_GetDomainSocketSizes) DllImportEntry(SystemNative_GetMaximumAddressSize) diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c index 82e3960e6fc335..052bc7ede9d2ea 100644 --- a/src/native/libs/System.Native/pal_networking.c +++ b/src/native/libs/System.Native/pal_networking.c @@ -1553,15 +1553,18 @@ int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeade } ssize_t res; -#if !defined(CMSG_SPACE) - // TODO https://github.com/dotnet/runtime/issues/98957 - return Error_ENOTSUP; -#else // !CMSG_SPACE +#if defined(CMSG_SPACE) struct msghdr header; ConvertMessageHeaderToMsghdr(&header, messageHeader, fd); while ((res = recvmsg(fd, &header, socketFlags)) < 0 && errno == EINTR); +#else // CMSG_SPACE + // we will only use 0th buffer + struct iovec* msg_iov = (struct iovec*)messageHeader->IOVectors; + while ((res = recvfrom(fd, msg_iov[0].iov_base, msg_iov[0].iov_len, socketFlags, (sockaddr *)messageHeader->SocketAddress, (socklen_t*) &(messageHeader->SocketAddressLen))) < 0 && errno == EINTR); +#endif // CMSG_SPACE +#if defined(CMSG_SPACE) assert(header.msg_name == messageHeader->SocketAddress); // should still be the same location as set in ConvertMessageHeaderToMsghdr assert(header.msg_control == messageHeader->ControlBuffer); @@ -1572,6 +1575,7 @@ int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeade messageHeader->ControlBufferLen = Min((int32_t)header.msg_controllen, messageHeader->ControlBufferLen); messageHeader->Flags = ConvertSocketFlagsPlatformToPal(header.msg_flags); +#endif // CMSG_SPACE if (res != -1) { @@ -1581,7 +1585,6 @@ int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeade *received = 0; return SystemNative_ConvertErrorPlatformToPal(errno); -#endif // !CMSG_SPACE } int32_t SystemNative_Send(intptr_t socket, void* buffer, int32_t bufferLen, int32_t flags, int32_t* sent) @@ -1635,11 +1638,8 @@ int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, return Error_ENOTSUP; } -#if !defined(CMSG_SPACE) - // TODO https://github.com/dotnet/runtime/issues/98957 - return Error_ENOTSUP; -#else // !CMSG_SPACE ssize_t res; +#if defined(CMSG_SPACE) struct msghdr header; ConvertMessageHeaderToMsghdr(&header, messageHeader, fd); @@ -1652,6 +1652,12 @@ int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, #else while ((res = sendmsg(fd, &header, socketFlags)) < 0 && errno == EINTR); #endif +#else // CMSG_SPACE + // we will only use 0th buffer + struct iovec* msg_iov = (struct iovec*)messageHeader->IOVectors; + while ((res = sendto(fd, msg_iov[0].iov_base, msg_iov[0].iov_len, socketFlags, (sockaddr *)messageHeader->SocketAddress, (socklen_t)messageHeader->SocketAddressLen)) < 0 && errno == EINTR); +#endif // CMSG_SPACE + if (res != -1) { *sent = res; @@ -1660,7 +1666,6 @@ int32_t SystemNative_SendMessage(intptr_t socket, MessageHeader* messageHeader, *sent = 0; return SystemNative_ConvertErrorPlatformToPal(errno); -#endif // !CMSG_SPACE } int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* socketAddressLen, intptr_t* acceptedSocket) @@ -1678,6 +1683,7 @@ int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* so while ((accepted = accept4(fd, (struct sockaddr*)socketAddress, &addrLen, SOCK_CLOEXEC)) < 0 && errno == EINTR); #else while ((accepted = accept(fd, (struct sockaddr*)socketAddress, &addrLen)) < 0 && errno == EINTR); +#if !defined(TARGET_WASI) // WASI is always FD_CLOEXEC and non-blocking #if defined(FD_CLOEXEC) // macOS does not have accept4 but it can set _CLOEXEC on descriptor. // Unlike accept4 it is not atomic and the fd can leak child process. @@ -1701,6 +1707,7 @@ int32_t SystemNative_Accept(intptr_t socket, uint8_t* socketAddress, int32_t* so accepted = -1; errno = oldErrno; } +#endif #endif if (accepted == -1) { @@ -2778,6 +2785,9 @@ int32_t SystemNative_Socket(int32_t addressFamily, int32_t socketType, int32_t p #ifdef SOCK_CLOEXEC platformSocketType |= SOCK_CLOEXEC; +#endif +#if defined(TARGET_WASI) + platformSocketType |= SOCK_NONBLOCK; // WASI sockets are always non-blocking, because in ST we don't have another thread which could be blocked #endif *createdSocket = socket(platformAddressFamily, platformSocketType, platformProtocolType); if (*createdSocket == -1) @@ -2841,6 +2851,11 @@ int32_t SystemNative_GetSocketType(intptr_t socket, int32_t* addressFamily, int3 !TryConvertSocketTypePlatformToPal(typeValue, socketType)) #endif { +#if defined(TARGET_WASI) + if (errno == EBADF){ + return Error_ENOTSOCK; + } +#endif // TARGET_WASI *socketType = SocketType_UNKNOWN; } @@ -3303,7 +3318,8 @@ static int32_t WaitForSocketEventsInner(int32_t port, SocketEvent* buffer, int32 return Error_SUCCESS; } -#else +#else // !HAVE_KQUEUE !HAVE_EPOLL + static const size_t SocketEventBufferElementSize = 0; static int32_t CloseSocketEventPortInner(int32_t port) @@ -3324,8 +3340,32 @@ static int32_t WaitForSocketEventsInner(int32_t port, SocketEvent* buffer, int32 { return Error_ENOSYS; } +#endif // !HAVE_KQUEUE !HAVE_EPOLL -#endif +#if defined(TARGET_WASI) +// from https://github.com/WebAssembly/wasi-libc/blob/230d4be6c54bec93181050f9e25c87150506bdd0/libc-bottom-half/headers/private/wasi/descriptor_table.h +bool descriptor_table_get_ref(int fd, void **entry); + +int32_t SystemNative_GetWasiSocketDescriptor(intptr_t socket, void** entry) +{ + if (entry == NULL) + { + return Error_EFAULT; + } + + int fd = ToFileDescriptor(socket); + if(!descriptor_table_get_ref(fd, entry)) + { + return Error_EFAULT; + } + return Error_SUCCESS; +} +#else +int32_t SystemNative_GetWasiSocketDescriptor(intptr_t socket, void** entry) +{ + return Error_ENOSYS; +} +#endif // TARGET_WASI int32_t SystemNative_CreateSocketEventPort(intptr_t* port) { diff --git a/src/native/libs/System.Native/pal_networking.h b/src/native/libs/System.Native/pal_networking.h index 8044ce00b02664..c393a3dbad4619 100644 --- a/src/native/libs/System.Native/pal_networking.h +++ b/src/native/libs/System.Native/pal_networking.h @@ -404,6 +404,8 @@ PALEXPORT int32_t SystemNative_GetAtOutOfBandMark(intptr_t socket, int32_t* avai PALEXPORT int32_t SystemNative_GetBytesAvailable(intptr_t socket, int32_t* available); +PALEXPORT int32_t SystemNative_GetWasiSocketDescriptor(intptr_t socket, void** entry); + PALEXPORT int32_t SystemNative_CreateSocketEventPort(intptr_t* port); PALEXPORT int32_t SystemNative_CloseSocketEventPort(intptr_t port); From aed1db14f6b5c3458208da4868c5e6849b5430e2 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 24 Sep 2024 00:54:51 +0200 Subject: [PATCH 03/14] unit tests --- .../System/IO/StreamConformanceTests.cs | 28 +++++++++ .../NamedPipeTest.UnixDomainSockets.cs | 1 + .../tests/FunctionalTests/Accept.cs | 13 ++-- .../FunctionalTests/AgnosticListenerTest.cs | 8 +-- .../ArgumentValidationTests.cs | 1 + .../tests/FunctionalTests/Connect.cs | 23 ++++--- .../FunctionalTests/CreateSocketTests.cs | 53 ++++++++++------ .../tests/FunctionalTests/DisconnectTest.cs | 9 ++- .../FunctionalTests/DisposedSocketTests.cs | 5 ++ .../tests/FunctionalTests/DnsEndPointTest.cs | 1 + .../FunctionalTests/DualModeSocketTest.cs | 24 ++++++++ .../FunctionalTests/EnableBroadcastTest.cs | 1 + .../ExecutionContextFlowTest.cs | 1 + .../IPPacketInformationTest.cs | 1 + .../tests/FunctionalTests/KeepAliveTest.cs | 4 +- .../tests/FunctionalTests/LingerStateTest.cs | 1 + .../FunctionalTests/LocalEndPointTest.cs | 36 +++++++++-- .../FunctionalTests/NetworkStreamTest.cs | 39 +++++++----- .../tests/FunctionalTests/OSSupport.cs | 2 + .../tests/FunctionalTests/ReceiveFrom.cs | 39 ++++++++---- .../FunctionalTests/ReceiveMessageFrom.cs | 22 +++++-- .../tests/FunctionalTests/SafeHandleTest.cs | 2 +- .../FunctionalTests/SelectAndPollTests.cs | 1 + .../tests/FunctionalTests/SelectTest.cs | 3 + .../tests/FunctionalTests/SendFile.cs | 30 ++++++--- .../tests/FunctionalTests/SendPacketsAsync.cs | 1 + .../FunctionalTests/SendPacketsElementTest.cs | 7 +++ .../SendReceive/SendReceive.cs | 26 ++++++-- .../SendReceive/SendReceiveMisc.cs | 12 ++-- .../SendReceive/SendReceiveNonParallel.cs | 5 ++ .../SendReceive/SendReceiveUdpClient.cs | 2 +- .../tests/FunctionalTests/SendTo.cs | 7 ++- .../tests/FunctionalTests/Shutdown.cs | 2 +- .../SocketAsyncEventArgsTest.cs | 22 ++++--- .../FunctionalTests/SocketDuplicationTests.cs | 2 + .../FunctionalTests/SocketOptionNameTest.cs | 2 + .../System.Net.Sockets.Tests.csproj | 3 +- .../tests/FunctionalTests/TcpClientTest.cs | 28 +++++++-- .../tests/FunctionalTests/TcpListenerTest.cs | 19 ++++-- .../tests/FunctionalTests/TelemetryTest.cs | 4 +- .../tests/FunctionalTests/TimeoutTest.cs | 1 + .../tests/FunctionalTests/UdpClientTest.cs | 58 ++++++++++++------ .../FunctionalTests/UnixDomainSocketTest.cs | 1 + src/libraries/tests.proj | 1 + src/mono/sample/wasi/sockets-p2/Program.cs | 61 +++++++++++++++++++ .../Wasip2.Sockets.Console.Sample.csproj | 13 ++++ 46 files changed, 487 insertions(+), 138 deletions(-) create mode 100644 src/mono/sample/wasi/sockets-p2/Program.cs create mode 100644 src/mono/sample/wasi/sockets-p2/Wasip2.Sockets.Console.Sample.csproj diff --git a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs index c36ce7c6feb0a0..c88f3e62235a69 100644 --- a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs +++ b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs @@ -1612,6 +1612,7 @@ protected static bool Bidirectional(StreamPair streams) => [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ArgumentValidation_ThrowsExpectedException() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1625,6 +1626,7 @@ public virtual async Task ArgumentValidation_ThrowsExpectedException() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Disposed_ThrowsObjectDisposedException() { StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1639,6 +1641,7 @@ public virtual async Task Disposed_ThrowsObjectDisposedException() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWriteAsync_PrecanceledOperations_ThrowsCancellationException() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1654,6 +1657,7 @@ public virtual async Task ReadWriteAsync_PrecanceledOperations_ThrowsCancellatio [InlineData(100)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_CancelPendingTask_ThrowsCancellationException(int cancellationDelay) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1667,6 +1671,7 @@ public virtual async Task ReadAsync_CancelPendingTask_ThrowsCancellationExceptio [InlineData(100)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_CancelPendingValueTask_ThrowsCancellationException(int cancellationDelay) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1678,6 +1683,7 @@ public virtual async Task ReadAsync_CancelPendingValueTask_ThrowsCancellationExc [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWriteByte_Success() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1753,6 +1759,7 @@ public virtual async Task ReadWrite_Success_Large(ReadWriteMode mode, int writeS [MemberData(nameof(ReadWrite_Success_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_Success(ReadWriteMode mode, int writeSize, bool startWithFlush) { foreach (CancellationToken nonCanceledToken in new[] { CancellationToken.None, new CancellationTokenSource().Token }) @@ -1811,6 +1818,7 @@ public virtual async Task ReadWrite_Success(ReadWriteMode mode, int writeSize, b [MemberData(nameof(ReadWrite_Modes))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_MessagesSmallerThanReadBuffer_Success(ReadWriteMode mode) { if (!FlushGuaranteesAllDataWritten) @@ -1861,6 +1869,7 @@ public virtual async Task ReadWrite_MessagesSmallerThanReadBuffer_Success(ReadWr [MemberData(nameof(AllReadWriteModesAndValue), true)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Read_Eof_Returns0(ReadWriteMode mode, bool dataAvailableFirst) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1901,6 +1910,7 @@ public virtual async Task Read_Eof_Returns0(ReadWriteMode mode, bool dataAvailab [InlineData(ReadWriteMode.AsyncAPM)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Read_DataStoredAtDesiredOffset(ReadWriteMode mode) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1932,6 +1942,7 @@ public virtual async Task Read_DataStoredAtDesiredOffset(ReadWriteMode mode) [InlineData(ReadWriteMode.AsyncAPM)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Write_DataReadFromDesiredOffset(ReadWriteMode mode) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1977,6 +1988,7 @@ public virtual async Task WriteWithBrokenPipe_Throws() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_NonReusableValueTask_AwaitMultipleTimes_Throws() { if (!ReadWriteValueTasksProtectSingleConsumption) @@ -2006,6 +2018,7 @@ public virtual async Task ReadAsync_NonReusableValueTask_AwaitMultipleTimes_Thro } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_NonReusableValueTask_MultipleContinuations_Throws() { if (!ReadWriteValueTasksProtectSingleConsumption) @@ -2032,6 +2045,7 @@ public static IEnumerable ReadAsync_ContinuesOnCurrentContextIfDesired [MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_ContinuesOnCurrentSynchronizationContextIfDesired(bool flowExecutionContext, bool? continueOnCapturedContext) { using StreamPair streams = await CreateConnectedStreamsAsync().ConfigureAwait(ConfigureAwaitOptions.ForceYielding /* escape xunit sync ctx */); @@ -2114,6 +2128,7 @@ public virtual async Task ReadAsync_ContinuesOnCurrentSynchronizationContextIfDe [MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_ContinuesOnCurrentTaskSchedulerIfDesired(bool flowExecutionContext, bool? continueOnCapturedContext) { using StreamPair streams = await CreateConnectedStreamsAsync().ConfigureAwait(ConfigureAwaitOptions.ForceYielding /* escape xunit sync ctx */); @@ -2203,6 +2218,7 @@ await Task.Factory.StartNew(() => [InlineData(ReadWriteMode.AsyncAPM)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ZeroByteRead_BlocksUntilDataAvailableOrNops(ReadWriteMode mode) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2271,6 +2287,7 @@ public virtual async Task ZeroByteRead_BlocksUntilDataAvailableOrNops(ReadWriteM [InlineData(ReadWriteMode.AsyncAPM)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ZeroByteWrite_OtherDataReceivedSuccessfully(ReadWriteMode mode) { byte[][] buffers = new[] { Array.Empty(), "hello"u8.ToArray(), Array.Empty(), "world"u8.ToArray() }; @@ -2326,6 +2343,7 @@ public virtual async Task ZeroByteWrite_OtherDataReceivedSuccessfully(ReadWriteM [InlineData(true)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_CustomMemoryManager_Success(bool useAsync) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2392,6 +2410,7 @@ await readable.ReadAsync(readBuffer.Memory.Slice(bytesRead)) : [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ConcurrentBidirectionalReadsWrites_Success() { if (!SupportsConcurrentBidirectionalUse) @@ -2451,6 +2470,7 @@ public virtual async Task CopyToAsync_AllDataCopied_Large(bool useAsync) => [MemberData(nameof(CopyToAsync_AllDataCopied_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task CopyToAsync_AllDataCopied(int byteCount, bool useAsync) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2481,6 +2501,7 @@ public virtual async Task CopyToAsync_AllDataCopied(int byteCount, bool useAsync [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Parallel_ReadWriteMultipleStreamsConcurrently() { await Task.WhenAll(Enumerable.Range(0, 20).Select(_ => Task.Run(async () => @@ -2492,6 +2513,7 @@ await Task.WhenAll(Enumerable.Range(0, 20).Select(_ => Task.Run(async () => [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Timeout_Roundtrips() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2528,6 +2550,7 @@ public virtual async Task Timeout_Roundtrips() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadTimeout_Expires_Throws() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2546,6 +2569,7 @@ public virtual async Task ReadTimeout_Expires_Throws() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_CancelPendingRead_DoesntImpactSubsequentReads() { if (!UsableAfterCanceledReads) @@ -2644,6 +2668,7 @@ public virtual async Task ClosedConnection_WritesFailImmediately_ThrowException( [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_DuringReadAsync_ThrowsIfUnsupported() { if (UnsupportedConcurrentExceptionType is null) @@ -2666,6 +2691,7 @@ public virtual async Task ReadAsync_DuringReadAsync_ThrowsIfUnsupported() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Flush_ValidOnWriteableStreamWithNoData_Success() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2682,6 +2708,7 @@ public virtual async Task Flush_ValidOnWriteableStreamWithNoData_Success() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Flush_ValidOnReadableStream_Success() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2701,6 +2728,7 @@ public virtual async Task Flush_ValidOnReadableStream_Success() [InlineData(2)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Dispose_ClosesStream(int disposeMode) { if (!CansReturnFalseAfterDispose) diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs index b5d182a28b55c5..b465b5158fc96a 100644 --- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs +++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs @@ -7,6 +7,7 @@ namespace System.IO.Pipes.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support UnixDomain")] public class NamedPipeTest_UnixDomainSockets { [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs index 819c3bc111027d..a556bea2295803 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs @@ -144,7 +144,7 @@ public async Task Accept_ConcurrentAcceptsAfterConnects_Success(int numberAccept } [OuterLoop] - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task Accept_WithTargetSocket_Success() { if (!SupportsAcceptIntoExistingSocket) @@ -167,7 +167,7 @@ public async Task Accept_WithTargetSocket_Success() } [OuterLoop] - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public async Task Accept_WithTargetSocket_ReuseAfterDisconnect_Success(bool reuseSocket) @@ -239,7 +239,7 @@ public async Task Accept_WithAlreadyBoundTargetSocket_Fails() } [OuterLoop] - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task Accept_WithInUseTargetSocket_Fails() { if (!SupportsAcceptIntoExistingSocket) @@ -264,6 +264,7 @@ public async Task Accept_WithInUseTargetSocket_Fails() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task AcceptAsync_MultipleAcceptsThenDispose_AcceptsThrowAfterDispose() { if (UsesSync) @@ -299,6 +300,7 @@ public async Task AcceptAsync_MultipleAcceptsThenDispose_AcceptsThrowAfterDispos [Theory] [MemberData(nameof(AcceptGetsCanceledByDispose_Data))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] [ActiveIssue("https://github.com/dotnet/runtime/issues/73536", TestPlatforms.iOS | TestPlatforms.tvOS)] public async Task AcceptGetsCanceledByDispose(IPAddress loopback, bool owning) { @@ -352,7 +354,7 @@ await RetryHelper.ExecuteAsync(async () => }, maxAttempts: 10, retryWhen: e => e is XunitException); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task AcceptReceive_Success() { if (!SupportsAcceptReceive) @@ -377,11 +379,13 @@ public async Task AcceptReceive_Success() } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class AcceptSync : Accept { public AcceptSync(ITestOutputHelper output) : base(output) {} } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class AcceptSyncForceNonBlocking : Accept { public AcceptSyncForceNonBlocking(ITestOutputHelper output) : base(output) {} @@ -464,6 +468,7 @@ public async Task AcceptAsync_Precanceled_Throws() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task AcceptAsync_CanceledDuringOperation_Throws() { using (Socket listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/AgnosticListenerTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/AgnosticListenerTest.cs index 5df4c048a37f9c..fd0d0831608991 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/AgnosticListenerTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/AgnosticListenerTest.cs @@ -31,7 +31,7 @@ public void Create_Success() } [OuterLoop] - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task ConnectWithV4_Success() { TcpListener listener = SocketTestExtensions.CreateAndStartTcpListenerOnAnonymousPort(out int port); @@ -48,7 +48,7 @@ public async Task ConnectWithV4_Success() } [OuterLoop] - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task ConnectWithV6_Success() { TcpListener listener = SocketTestExtensions.CreateAndStartTcpListenerOnAnonymousPort(out int port); @@ -65,7 +65,7 @@ public async Task ConnectWithV6_Success() } [OuterLoop] - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task ConnectWithV4AndV6_Success() { TcpListener listener = SocketTestExtensions.CreateAndStartTcpListenerOnAnonymousPort(out int port); @@ -110,7 +110,7 @@ public void StaticCreate_Success() IPEndPoint ep = (IPEndPoint)listener.LocalEndpoint; Assert.Equal(ep.Address, IPAddress.IPv6Any); Assert.Equal(0, ep.Port); - Assert.True(listener.Server.DualMode); + if (!OperatingSystem.IsWasi()) Assert.True(listener.Server.DualMode); listener.Start(); listener.Stop(); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs index deac6c8f2814d9..eb7739ea3674b0 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs @@ -11,6 +11,7 @@ namespace System.Net.Sockets.Tests { + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class ArgumentValidation { // This type is used to test Socket.Select's argument validation. diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs index dda67f84155459..dea2a2a19238ea 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs @@ -17,7 +17,7 @@ namespace System.Net.Sockets.Tests public Connect(ITestOutputHelper output) : base(output) {} [OuterLoop] - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads [MemberData(nameof(Loopbacks))] public async Task Connect_Success(IPAddress listenAt) { @@ -45,7 +45,7 @@ public async Task Connect_Udp_Success(IPAddress listenAt) Assert.True(client.Connected); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads [MemberData(nameof(Loopbacks))] public async Task Connect_Dns_Success(IPAddress listenAt) { @@ -68,7 +68,7 @@ public async Task Connect_Dns_Success(IPAddress listenAt) } [OuterLoop] - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads [MemberData(nameof(Loopbacks))] public async Task Connect_MultipleIPAddresses_Success(IPAddress listenAt) { @@ -85,7 +85,7 @@ public async Task Connect_MultipleIPAddresses_Success(IPAddress listenAt) } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads public async Task Connect_OnConnectedSocket_Fails() { int port; @@ -102,7 +102,7 @@ public async Task Connect_OnConnectedSocket_Fails() [PlatformSpecific(TestPlatforms.Windows)] // Unix currently does not support Disconnect [OuterLoop] - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads public async Task Connect_AfterDisconnect_Fails() { int port; @@ -205,6 +205,7 @@ await RetryHelper.ExecuteAsync(async () => [OuterLoop("Connection failure takes long on Windows.")] [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task Connect_WithoutListener_ThrowSocketExceptionWithAppropriateInfo() { using PortBlocker portBlocker = new PortBlocker(() => @@ -227,6 +228,7 @@ public async Task Connect_WithoutListener_ThrowSocketExceptionWithAppropriateInf [Theory] [MemberData(nameof(LoopbacksAndAny))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task Connect_DatagramSockets_DontThrowConnectedException_OnSecondAttempt(IPAddress listenAt, IPAddress secondConnection) { using Socket listener = new Socket(listenAt.AddressFamily, SocketType.Dgram, ProtocolType.Udp); @@ -241,16 +243,19 @@ public async Task Connect_DatagramSockets_DontThrowConnectedException_OnSecondAt } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ConnectSync : Connect { public ConnectSync(ITestOutputHelper output) : base(output) {} } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ConnectSyncForceNonBlocking : Connect { public ConnectSyncForceNonBlocking(ITestOutputHelper output) : base(output) {} } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ConnectApm : Connect { public ConnectApm(ITestOutputHelper output) : base(output) {} @@ -265,7 +270,7 @@ public sealed class ConnectEap : Connect { public ConnectEap(ITestOutputHelper output) : base(output) {} - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(true)] [InlineData(false)] public async Task ConnectAsync_WithData_DataReceived(bool useArrayApi) @@ -484,7 +489,7 @@ protected Connect_NonParallel(ITestOutputHelper output) : base(output) { } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads public async Task Connect_DualMode_MultiAddressFamilyConnect_RetrievedEndPoints_Success() { if (!SupportsMultiConnect) @@ -503,7 +508,7 @@ public async Task Connect_DualMode_MultiAddressFamilyConnect_RetrievedEndPoints_ } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads public async Task Connect_DualMode_DnsConnect_RetrievedEndPoints_Success() { var localhostAddresses = Dns.GetHostAddresses("localhost"); @@ -539,11 +544,13 @@ public sealed class ConnectSync_NonParallel : Connect_NonParallel { public ConnectSyncForceNonBlocking_NonParallel(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ConnectApm_NonParallel : Connect_NonParallel { public ConnectApm_NonParallel(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs index c31a2bd89a1e0f..8ba08e9cfdbdca 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs @@ -40,7 +40,7 @@ public CreateSocket(ITestOutputHelper output) new object[] { SocketType.Unknown, ProtocolType.Udp }, }; - private static bool SupportsRawSockets => Environment.IsPrivilegedProcess; + private static bool SupportsRawSockets => Environment.IsPrivilegedProcess && !OperatingSystem.IsWasi(); private static bool NotSupportsRawSockets => !SupportsRawSockets; [OuterLoop] @@ -118,6 +118,7 @@ public void Ctor_Raw_Supported_Success(AddressFamily addressFamily, ProtocolType [InlineData(AddressFamily.InterNetworkV6, ProtocolType.Udp)] [InlineData(AddressFamily.InterNetworkV6, ProtocolType.IcmpV6)] [ConditionalTheory(nameof(NotSupportsRawSockets))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public void Ctor_Raw_NotSupported_ExpectedError(AddressFamily addressFamily, ProtocolType protocolType) { SocketException e = Assert.Throws(() => new Socket(addressFamily, SocketType.Raw, protocolType)); @@ -277,6 +278,17 @@ public void Ctor_Socket_FromPipeHandle_Ctor_Dispose_Success(bool ownsHandle) [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] public void Ctor_SafeHandle_BasicPropertiesPropagate_Success(AddressFamily addressFamily, SocketType socketType, ProtocolType protocolType) { + if(OperatingSystem.IsWasi() && addressFamily == AddressFamily.Unix) + { + // WASI doesn't support Unix domain sockets. + return; + } + if(OperatingSystem.IsWasi() && socketType == SocketType.Raw) + { + // WASI doesn't support Raw sockets. + return; + } + bool isRawPacket = (addressFamily == AddressFamily.Packet) && (socketType == SocketType.Raw); if (isRawPacket) @@ -357,8 +369,8 @@ public void Ctor_SafeHandle_BasicPropertiesPropagate_Success(AddressFamily addre } Assert.Equal(expectedProtocolType, copy.ProtocolType); - Assert.True(orig.Blocking); - Assert.True(copy.Blocking); + if (!OperatingSystem.IsWasi()) Assert.True(orig.Blocking); + if (!OperatingSystem.IsWasi()) Assert.True(copy.Blocking); if (orig.AddressFamily == copy.AddressFamily) { @@ -372,13 +384,13 @@ public void Ctor_SafeHandle_BasicPropertiesPropagate_Success(AddressFamily addre AssertEqualOrSameException(() => orig.LingerState.LingerTime, () => copy.LingerState.LingerTime); AssertEqualOrSameException(() => orig.NoDelay, () => copy.NoDelay); - Assert.Equal(orig.Available, copy.Available); - Assert.Equal(orig.ExclusiveAddressUse, copy.ExclusiveAddressUse); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.Available, copy.Available); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.ExclusiveAddressUse, copy.ExclusiveAddressUse); Assert.Equal(orig.Handle, copy.Handle); Assert.Equal(orig.ReceiveBufferSize, copy.ReceiveBufferSize); - Assert.Equal(orig.ReceiveTimeout, copy.ReceiveTimeout); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.ReceiveTimeout, copy.ReceiveTimeout); Assert.Equal(orig.SendBufferSize, copy.SendBufferSize); - Assert.Equal(orig.SendTimeout, copy.SendTimeout); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.SendTimeout, copy.SendTimeout); #pragma warning disable 0618 Assert.Equal(orig.UseOnlyOverlappedIO, copy.UseOnlyOverlappedIO); #pragma warning restore 0618 @@ -409,27 +421,29 @@ public async Task Ctor_SafeHandle_Tcp_SendReceive_Success(AddressFamily addressF Assert.Equal(orig.RemoteEndPoint, client.RemoteEndPoint); // Validating accessing other properties - Assert.Equal(orig.Available, client.Available); - Assert.True(orig.Blocking); - Assert.True(client.Blocking); + if (!OperatingSystem.IsWasi()) // https://github.com/WebAssembly/wasi-libc/issues/538 + Assert.Equal(orig.Available, client.Available); + if (!OperatingSystem.IsWasi()) Assert.True(orig.Blocking); + if (!OperatingSystem.IsWasi()) Assert.True(client.Blocking); AssertEqualOrSameException(() => orig.DontFragment, () => client.DontFragment); AssertEqualOrSameException(() => orig.EnableBroadcast, () => client.EnableBroadcast); - Assert.Equal(orig.ExclusiveAddressUse, client.ExclusiveAddressUse); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.ExclusiveAddressUse, client.ExclusiveAddressUse); Assert.Equal(orig.Handle, client.Handle); Assert.Equal(orig.IsBound, client.IsBound); - Assert.Equal(orig.LingerState.Enabled, client.LingerState.Enabled); - Assert.Equal(orig.LingerState.LingerTime, client.LingerState.LingerTime); - AssertEqualOrSameException(() => orig.MulticastLoopback, () => client.MulticastLoopback); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.LingerState.Enabled, client.LingerState.Enabled); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.LingerState.LingerTime, client.LingerState.LingerTime); + if (!OperatingSystem.IsWasi()) AssertEqualOrSameException(() => orig.MulticastLoopback, () => client.MulticastLoopback); Assert.Equal(orig.NoDelay, client.NoDelay); Assert.Equal(orig.ReceiveBufferSize, client.ReceiveBufferSize); - Assert.Equal(orig.ReceiveTimeout, client.ReceiveTimeout); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.ReceiveTimeout, client.ReceiveTimeout); Assert.Equal(orig.SendBufferSize, client.SendBufferSize); - Assert.Equal(orig.SendTimeout, client.SendTimeout); + if (!OperatingSystem.IsWasi()) Assert.Equal(orig.SendTimeout, client.SendTimeout); Assert.Equal(orig.Ttl, client.Ttl); // Validate setting various properties on the new instance and seeing them roundtrip back to the original. - client.ReceiveTimeout = 42; - Assert.Equal(client.ReceiveTimeout, orig.ReceiveTimeout); + if (!OperatingSystem.IsWasi()) // https://github.com/WebAssembly/wasi-libc/issues/539 + client.ReceiveTimeout = 42; + if (!OperatingSystem.IsWasi()) Assert.Equal(client.ReceiveTimeout, orig.ReceiveTimeout); // Validate sending and receiving Assert.Equal(1, await client.SendAsync(new byte[1] { 42 }, SocketFlags.None)); @@ -443,7 +457,7 @@ public async Task Ctor_SafeHandle_Tcp_SendReceive_Success(AddressFamily addressF Assert.Equal(42, buffer[0]); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] @@ -660,6 +674,7 @@ private static unsafe (int, int) pipe2(int flags = 0) [Fact] [PlatformSpecific(TestPlatforms.AnyUnix)] [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public unsafe void Ctor_SafeHandle_SocketPair_Success() { // This is platform dependent but it seems like this is same on all supported platforms. diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisconnectTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisconnectTest.cs index 1c0270eaca6bd9..9fe7f43c703b29 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisconnectTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DisconnectTest.cs @@ -13,7 +13,7 @@ namespace System.Net.Sockets.Tests { protected Disconnect(ITestOutputHelper output) : base(output) { } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads [InlineData(true)] [InlineData(false)] public async Task Disconnect_Success(bool reuseSocket) @@ -50,7 +50,7 @@ public async Task Disconnect_Success(bool reuseSocket) } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // async SocketTestServer requires threads public async Task DisconnectAndReuse_ReconnectSync_ThrowsInvalidOperationException() { IPEndPoint loopback = new IPEndPoint(IPAddress.Loopback, 0); @@ -97,16 +97,19 @@ public void Disconnect_ObjectDisposed_ThrowsObjectDisposedException(bool reuseSo } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class Disconnect_Sync : Disconnect { public Disconnect_Sync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class Disconnect_SyncForceNonBlocking : Disconnect { public Disconnect_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class Disconnect_Apm : Disconnect { public Disconnect_Apm(ITestOutputHelper output) : base(output) { } @@ -131,7 +134,7 @@ public sealed class Disconnect_CancellableTask : Disconnect(() => GetDisposedSocket().LingerState); } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support Linger")] public void SetLingerState_Throws_ObjectDisposed() { Assert.Throws(() => @@ -258,12 +261,14 @@ public void SetEnableBroadcast_Throws_ObjectDisposed() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public void DualMode_Throws_ObjectDisposed() { Assert.Throws(() => GetDisposedSocket(AddressFamily.InterNetworkV6).DualMode); } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public void SetDualMode_Throws_ObjectDisposed() { Assert.Throws(() => diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DnsEndPointTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DnsEndPointTest.cs index f23a1e835b7be3..c1b74b2caf3d57 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DnsEndPointTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DnsEndPointTest.cs @@ -11,6 +11,7 @@ namespace System.Net.Sockets.Tests { using Configuration = System.Net.Test.Common.Configuration; + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class DnsEndPointTest : DualModeBase { private void OnConnectAsyncCompleted(object sender, SocketAsyncEventArgs args) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs index 17c5a3e18240b6..4c3fe672804612 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/DualModeSocketTest.cs @@ -15,6 +15,7 @@ namespace System.Net.Sockets.Tests { [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConstructorAndProperty : DualModeBase { [Fact] @@ -76,6 +77,7 @@ public void IPv4Constructor_DualMode_SetterThrows() [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectToIPAddress : DualModeBase { [Fact] // Base case @@ -168,6 +170,7 @@ private void DualModeConnect_IPAddressToHost_Fails_Helper(IPAddress connectTo, I [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectToIPEndPoint : DualModeBase { [Fact] // Base case @@ -260,6 +263,7 @@ private void DualModeConnect_IPEndPointToHost_Fails_Helper(IPAddress connectTo, [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectToIPAddressArray : DualModeBase { [Fact] // Base Case @@ -325,6 +329,7 @@ public void DualModeConnect_IPAddressListToHost_Success(IPAddress[] connectTo, I [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectToHostString : DualModeBase { [ConditionalTheory(nameof(LocalhostIsBothIPv4AndIPv6))] @@ -343,6 +348,7 @@ public void DualModeConnect_LoopbackDnsToHost_Helper(IPAddress listenOn, bool du [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectToDnsEndPoint : DualModeBase { [ConditionalTheory(nameof(LocalhostIsBothIPv4AndIPv6))] @@ -361,6 +367,7 @@ public void DualModeConnect_DnsEndPointToHost_Helper(IPAddress listenOn, bool du [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeBeginConnectToIPAddress : DualModeBase { [Fact] // Base case @@ -425,6 +432,7 @@ private async Task DualModeBeginConnect_IPAddressToHost_Fails_Helper(IPAddress c [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeBeginConnectToIPEndPoint : DualModeBase { [Fact] @@ -463,6 +471,7 @@ private async Task DualModeBeginConnect_IPEndPointToHost_Helper(IPAddress connec [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeBeginConnect : DualModeBase { [Theory] @@ -510,6 +519,7 @@ public async Task DualModeBeginConnect_DnsEndPointToHost_Helper(IPAddress listen [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectAsync : DualModeBase { [Fact] // Base case @@ -659,6 +669,7 @@ public void DualModeConnectAsync_Static_DnsEndPointToHost_Helper(IPAddress liste [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeBind : DualModeBase { [Fact] @@ -812,6 +823,7 @@ protected static void AssertDualModeEnabled(Socket socket, IPAddress listenOn) [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeAcceptSync : DualModeAcceptBase { public DualModeAcceptSync(ITestOutputHelper output) : base(output) { } @@ -819,6 +831,7 @@ public DualModeAcceptSync(ITestOutputHelper output) : base(output) { } [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeAcceptApm : DualModeAcceptBase { public DualModeAcceptApm(ITestOutputHelper output) : base(output) { } @@ -826,6 +839,7 @@ public DualModeAcceptApm(ITestOutputHelper output) : base(output) { } [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeAcceptEap : DualModeAcceptBase { public DualModeAcceptEap(ITestOutputHelper output) : base(output) { } @@ -833,6 +847,7 @@ public DualModeAcceptEap(ITestOutputHelper output) : base(output) { } [Trait("IPv4", "true")] [Trait("IPv6", "true")] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeAcceptTask : DualModeAcceptBase { public DualModeAcceptTask(ITestOutputHelper output) : base(output) { } @@ -913,6 +928,7 @@ private async Task DualModeSendTo_IPEndPointToHost_Failing_Helper(IPAddress conn [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessSendToSync : DualModeConnectionlessSendToBase { public DualModeConnectionlessSendToSync(ITestOutputHelper output) : base(output) @@ -923,6 +939,7 @@ public DualModeConnectionlessSendToSync(ITestOutputHelper output) : base(output) [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessSendToApm : DualModeConnectionlessSendToBase { public DualModeConnectionlessSendToApm(ITestOutputHelper output) : base(output) @@ -933,6 +950,7 @@ public DualModeConnectionlessSendToApm(ITestOutputHelper output) : base(output) [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessSendToEap : DualModeConnectionlessSendToBase { public DualModeConnectionlessSendToEap(ITestOutputHelper output) : base(output) @@ -943,6 +961,7 @@ public DualModeConnectionlessSendToEap(ITestOutputHelper output) : base(output) [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessSendToTask : DualModeConnectionlessSendToBase { public DualModeConnectionlessSendToTask(ITestOutputHelper output) : base(output) @@ -1044,6 +1063,7 @@ protected async Task ReceiveFrom_Failure_Helper(IPAddress listenOn, IPAddress co [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessReceiveFromSync : DualModeConnectionlessReceiveFromBase { public DualModeConnectionlessReceiveFromSync(ITestOutputHelper output) : base(output) @@ -1054,6 +1074,7 @@ public DualModeConnectionlessReceiveFromSync(ITestOutputHelper output) : base(ou [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessReceiveFromApm : DualModeConnectionlessReceiveFromBase { public DualModeConnectionlessReceiveFromApm(ITestOutputHelper output) : base(output) @@ -1064,6 +1085,7 @@ public DualModeConnectionlessReceiveFromApm(ITestOutputHelper output) : base(out [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessReceiveFromEap : DualModeConnectionlessReceiveFromBase { public DualModeConnectionlessReceiveFromEap(ITestOutputHelper output) : base(output) @@ -1074,6 +1096,7 @@ public DualModeConnectionlessReceiveFromEap(ITestOutputHelper output) : base(out [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessReceiveFromTask : DualModeConnectionlessReceiveFromBase { public DualModeConnectionlessReceiveFromTask(ITestOutputHelper output) : base(output) @@ -1084,6 +1107,7 @@ public DualModeConnectionlessReceiveFromTask(ITestOutputHelper output) : base(ou [Trait("IPv4", "true")] [Trait("IPv6", "true")] [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public class DualModeConnectionlessReceiveMessageFrom : DualModeBase { [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/EnableBroadcastTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/EnableBroadcastTest.cs index bdb28d978630af..c5c7e75b45032f 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/EnableBroadcastTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/EnableBroadcastTest.cs @@ -5,6 +5,7 @@ namespace System.Net.Sockets.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support Broadcast")] public class EnableBroadcastTest { [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs index 41f473826bde40..d1a5908176b5c3 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ExecutionContextFlowTest.cs @@ -10,6 +10,7 @@ namespace System.Net.Sockets.Tests { + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class ExecutionContextFlowTest : FileCleanupTestBase { [Theory] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs index 1eda62921fb50d..60304407c4ec58 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs @@ -7,6 +7,7 @@ namespace System.Net.Sockets.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support IPPacketInformation")] public class IPPacketInformationTest { [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs index 572bd77ea77fa9..1ce2ecc707dec7 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/KeepAliveTest.cs @@ -128,7 +128,7 @@ public void Socket_Get_KeepAlive_Time_AsByteArray_OptionLengthZero_Failure() { using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { - if (PlatformDetection.IsWindows) + if (PlatformDetection.IsWindows || PlatformDetection.IsWasi) { Assert.Throws(() => socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, 0)); } @@ -153,7 +153,7 @@ public void Socket_Get_KeepAlive_Time_AsByteArray_BufferNullOrTooSmall_Failure(b using (Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) { - if (PlatformDetection.IsWindows) + if (PlatformDetection.IsWindows || PlatformDetection.IsWasi) { Assert.Throws(() => socket.GetSocketOption(SocketOptionLevel.Tcp, SocketOptionName.TcpKeepAliveTime, buffer)); } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs index 776b940d6ff1c8..8cbb2138bd666d 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LingerStateTest.cs @@ -6,6 +6,7 @@ namespace System.Net.Sockets.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support Linger")] public class LingerStateTest { private void TestLingerState_Success(Socket sock, bool enabled, int lingerTime) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs index 673e85b593e24e..208c78962782b5 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs @@ -45,11 +45,20 @@ public async Task UdpSocket_WhenBoundToWildcardAddress_LocalEPDoesNotChangeOnSen byte[] buf = new byte[3]; EndPoint receiveFromEP = new IPEndPoint(Wildcard, 0); - receiver.ReceiveFrom(buf, ref receiveFromEP); + + var tcs = new TaskCompletionSource(); + SocketAsyncEventArgs args = new SocketAsyncEventArgs(); + args.RemoteEndPoint = receiveFromEP; + args.SetBuffer(buf, 0, buf.Length); + args.Completed += (s, e) => tcs.SetResult(e.RemoteEndPoint); + if (receiver.ReceiveFromAsync(args)) + { + Assert.True(await Task.WhenAny(tcs.Task, Task.Delay(TestSettings.PassingTestTimeout)) == tcs.Task, "Timed out"); + } Assert.Equal(new byte[] { 1, 2, 3 }, buf); - Assert.Equal(Loopback, ((IPEndPoint)receiveFromEP).Address); // received from specific address - Assert.Equal(senderPortAfterBind, ((IPEndPoint)receiveFromEP).Port); + Assert.Equal(Loopback, ((IPEndPoint)args.RemoteEndPoint).Address); // received from specific address + Assert.Equal(senderPortAfterBind, ((IPEndPoint)args.RemoteEndPoint).Port); } } @@ -71,14 +80,24 @@ public async Task UdpSocket_WhenNotBound_LocalEPChangeToWildcardOnSendTo() byte[] buf = new byte[3]; EndPoint receiveFromEP = new IPEndPoint(Wildcard, 0); - receiver.ReceiveFrom(buf, ref receiveFromEP); + + var tcs = new TaskCompletionSource(); + SocketAsyncEventArgs args = new SocketAsyncEventArgs(); + args.RemoteEndPoint = receiveFromEP; + args.SetBuffer(buf, 0, buf.Length); + args.Completed += (s, e) => tcs.SetResult(e.RemoteEndPoint); + if (receiver.ReceiveFromAsync(args)) + { + Assert.True(await Task.WhenAny(tcs.Task, Task.Delay(TestSettings.PassingTestTimeout)) == tcs.Task, "Timed out"); + } Assert.Equal(new byte[] { 1, 2, 3 }, buf); - Assert.Equal(Loopback, ((IPEndPoint)receiveFromEP).Address); // received from specific address + Assert.Equal(Loopback, ((IPEndPoint)args.RemoteEndPoint).Address); // received from specific address } } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] // see also https://github.com/WebAssembly/wasi-libc/issues/540 public async Task TcpClientSocket_WhenBoundToWildcardAddress_LocalEPChangeToSpecificOnConnect() { using (Socket server = CreateTcpSocket()) @@ -124,6 +143,7 @@ public async Task TcpClientSocket_WhenNotBound_LocalEPChangeToSpecificOnConnect( } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] // see also https://github.com/WebAssembly/wasi-libc/issues/540 public async Task TcpAcceptSocket_WhenServerBoundToWildcardAddress_LocalEPIsSpecific() { using (Socket server = CreateTcpSocket()) @@ -228,18 +248,21 @@ public LocalEndPointTestIPv6(ITestOutputHelper output) : base(output) { } } [Trait("IPv4", "true")] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class LocalEndPointTestIPv4Sync : LocalEndPointTestIPv4 { public LocalEndPointTestIPv4Sync(ITestOutputHelper output) : base(output) { } } [Trait("IPv4", "true")] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class LocalEndPointTestIPv4SyncForceNonBlocking : LocalEndPointTestIPv4 { public LocalEndPointTestIPv4SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } [Trait("IPv4", "true")] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class LocalEndPointTestIPv4Apm : LocalEndPointTestIPv4 { public LocalEndPointTestIPv4Apm(ITestOutputHelper output) : base(output) { } @@ -258,18 +281,21 @@ public LocalEndPointTestIPv4Eap(ITestOutputHelper output) : base(output) { } } [Trait("IPv6", "true")] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class LocalEndPointTestIPv6Sync : LocalEndPointTestIPv6 { public LocalEndPointTestIPv6Sync(ITestOutputHelper output) : base(output) { } } [Trait("IPv6", "true")] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class LocalEndPointTestIPv6SyncForceNonBlocking : LocalEndPointTestIPv6 { public LocalEndPointTestIPv6SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } [Trait("IPv6", "true")] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class LocalEndPointTestIPv6Apm : LocalEndPointTestIPv6 { public LocalEndPointTestIPv6Apm(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs index a2df38adac5db5..21f39aa9104987 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs @@ -20,17 +20,17 @@ public class NetworkStreamTest : ConnectedStreamConformanceTests protected override bool FlushRequiredToWriteData => false; protected override Type UnsupportedConcurrentExceptionType => null; protected override bool ReadWriteValueTasksProtectSingleConsumption => true; - protected override Task CreateConnectedStreamsAsync() + protected override async Task CreateConnectedStreamsAsync() { using Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); listener.Bind(new IPEndPoint(IPAddress.Loopback, 0)); listener.Listen(); var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - client.Connect(listener.LocalEndPoint); - Socket server = listener.Accept(); + await client.ConnectAsync(listener.LocalEndPoint); + Socket server = await listener.AcceptAsync(); - return Task.FromResult((new NetworkStream(client, ownsSocket: true), new NetworkStream(server, ownsSocket: true))); + return (new NetworkStream(client, ownsSocket: true), new NetworkStream(server, ownsSocket: true)); } [Fact] @@ -75,7 +75,7 @@ public async Task Ctor_NonBlockingSocket_Throws() using (Socket server = await acceptTask) { server.Blocking = false; - Assert.Throws(() => new NetworkStream(server)); + if (!OperatingSystem.IsWasi()) Assert.Throws(() => new NetworkStream(server)); } } } @@ -246,8 +246,11 @@ public async Task Ctor_SocketFileAccess_CanReadAndWrite() Assert.Equal(1, await clientStream.ReadAsync(buffer, 0, 1)); Assert.Equal('a', (char)buffer[0]); - Assert.Throws(() => { serverStream.BeginRead(buffer, 0, 1, null, null); }); - Assert.Throws(() => { clientStream.BeginWrite(buffer, 0, 1, null, null); }); + if (!OperatingSystem.IsWasi()) + { + Assert.Throws(() => { serverStream.BeginRead(buffer, 0, 1, null, null); }); + Assert.Throws(() => { clientStream.BeginWrite(buffer, 0, 1, null, null); }); + } Assert.Throws(() => { serverStream.ReadAsync(buffer, 0, 1); }); Assert.Throws(() => { clientStream.WriteAsync(buffer, 0, 1); }); @@ -326,14 +329,14 @@ public async Task DisposeSocketDirectly_ReadWriteThrowNetworkException(bool deri serverSocket.Dispose(); - ExpectIOException(() => server.Read(new byte[1], 0, 1)); - ExpectIOException(() => server.Write(new byte[1], 0, 1)); + if (!OperatingSystem.IsWasi()) ExpectIOException(() => server.Read(new byte[1], 0, 1)); + if (!OperatingSystem.IsWasi()) ExpectIOException(() => server.Write(new byte[1], 0, 1)); - ExpectIOException(() => server.Read((Span)new byte[1])); - ExpectIOException(() => server.Write((ReadOnlySpan)new byte[1])); + if (!OperatingSystem.IsWasi()) ExpectIOException(() => server.Read((Span)new byte[1])); + if (!OperatingSystem.IsWasi()) ExpectIOException(() => server.Write((ReadOnlySpan)new byte[1])); - ExpectIOException(() => server.BeginRead(new byte[1], 0, 1, null, null)); - ExpectIOException(() => server.BeginWrite(new byte[1], 0, 1, null, null)); + if (!OperatingSystem.IsWasi()) ExpectIOException(() => server.BeginRead(new byte[1], 0, 1, null, null)); + if (!OperatingSystem.IsWasi()) ExpectIOException(() => server.BeginWrite(new byte[1], 0, 1, null, null)); ExpectIOException(() => { _ = server.ReadAsync(new byte[1], 0, 1); }); ExpectIOException(() => { _ = server.WriteAsync(new byte[1], 0, 1); }); @@ -377,7 +380,7 @@ public async Task ReadableWriteableProperties_Roundtrip() serverStream.Readable = false; Assert.False(serverStream.Readable); Assert.False(serverStream.CanRead); - Assert.Throws(() => serverStream.Read(new byte[1], 0, 1)); + await Assert.ThrowsAsync(() => serverStream.ReadAsync(new byte[1], 0, 1)); serverStream.Readable = true; Assert.True(serverStream.Readable); @@ -388,7 +391,7 @@ public async Task ReadableWriteableProperties_Roundtrip() serverStream.Writeable = false; Assert.False(serverStream.Writeable); Assert.False(serverStream.CanWrite); - Assert.Throws(() => serverStream.Write(new byte[1], 0, 1)); + await Assert.ThrowsAsync(() => serverStream.WriteAsync(new byte[1], 0, 1)); serverStream.Writeable = true; Assert.True(serverStream.Writeable); @@ -400,6 +403,7 @@ public async Task ReadableWriteableProperties_Roundtrip() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task CopyToAsync_DisposedSourceStream_ThrowsOnWindows_NoThrowOnUnix() { await RunWithConnectedNetworkStreamsAsync(async (stream, _) => @@ -437,6 +441,7 @@ await RunWithConnectedNetworkStreamsAsync((stream, _) => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ReadAsync_MultipleConcurrentValueTaskReads_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -457,6 +462,7 @@ await RunWithConnectedNetworkStreamsAsync(async (server, client) => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ReadAsync_MultipleConcurrentValueTaskReads_AsTask_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -477,6 +483,7 @@ await RunWithConnectedNetworkStreamsAsync(async (server, client) => } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task WriteAsync_MultipleConcurrentValueTaskWrites_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -503,6 +510,7 @@ await client.ReadAsync((Memory)b2) + } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task WriteAsync_MultipleConcurrentValueTaskWrites_AsTask_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -561,6 +569,7 @@ private static async Task RunWithConnectedNetworkStreamsAsync(Func(() => socket.ReceiveFrom(new byte[1], SocketFlags.None, socketAddress)); + } + + [Fact] + public async Task NullSocketAddress_Throws_ArgumentExceptionAsync() + { + using Socket socket = CreateSocket(); + SocketAddress socketAddress = null; + await Assert.ThrowsAsync(() => socket.ReceiveFromAsync(new Memory(new byte[1]), SocketFlags.None, socketAddress).AsTask()); } @@ -94,6 +102,7 @@ public async Task NotBound_Throws_InvalidOperationException() [Theory] [InlineData(false)] [InlineData(true)] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task ReceiveSent_TCP_Success(bool ipv6) { if (ipv6 && PlatformDetection.IsApplePlatform) @@ -151,7 +160,7 @@ public async Task ReceiveSent_UDP_Success(bool ipv4) for (int i = 0; i < DatagramsToSend; i++) { rnd.NextBytes(sendBuffer); - sender.SendTo(sendBuffer, receiver.LocalEndPoint); + await sender.SendToAsync(sendBuffer, receiver.LocalEndPoint); SocketReceiveFromResult result = await ReceiveFromAsync(receiver, receiveBuffer, remoteEp); @@ -171,6 +180,7 @@ public async Task ReceiveSent_UDP_Success(bool ipv4) [Theory] [InlineData(false)] [InlineData(true)] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support DualMode")] public async Task ReceiveSent_DualMode_Success(bool ipv4) { const int Offset = 10; @@ -217,7 +227,7 @@ public async Task ReceiveSent_DualMode_Success(bool ipv4) [Theory] [InlineData(false)] [InlineData(true)] - public void ReceiveSent_SocketAddress_Success(bool ipv4) + public async Task ReceiveSent_SocketAddress_Success(bool ipv4) { const int DatagramSize = 256; const int DatagramsToSend = 16; @@ -241,17 +251,17 @@ public void ReceiveSent_SocketAddress_Success(bool ipv4) for (int i = 0; i < DatagramsToSend; i++) { rnd.NextBytes(sendBuffer); - client.SendTo(sendBuffer.AsSpan(), SocketFlags.None, serverSA); + await client.SendToAsync(sendBuffer, SocketFlags.None, serverSA); - int readBytes = server.ReceiveFrom(receiveBuffer, SocketFlags.None, sa); + int readBytes = await server.ReceiveFromAsync(receiveBuffer, SocketFlags.None, sa); Assert.Equal(sa, clientSA); Assert.Equal(client.LocalEndPoint, client.LocalEndPoint.Create(sa)); Assert.True(new Span(receiveBuffer, 0, readBytes).SequenceEqual(sendBuffer)); // and send it back to make sure it works. rnd.NextBytes(sendBuffer); - server.SendTo(sendBuffer, SocketFlags.None, sa); - readBytes = client.ReceiveFrom(receiveBuffer, SocketFlags.None, sa); + await server.SendToAsync(sendBuffer, SocketFlags.None, sa); + readBytes = await client.ReceiveFromAsync(receiveBuffer, SocketFlags.None, sa); Assert.Equal(sa, serverSA); Assert.Equal(server.LocalEndPoint, server.LocalEndPoint.Create(sa)); Assert.True(new Span(receiveBuffer, 0, readBytes).SequenceEqual(sendBuffer)); @@ -303,7 +313,7 @@ public async Task ReceiveSent_SocketAddressAsync_Success(bool ipv4) } [Fact] - public void ReceiveSent_SmallSocketAddress_Throws() + public async Task ReceiveSent_SmallSocketAddress_Throws() { using Socket server = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); server.BindToAnonymousPort(IPAddress.Loopback); @@ -313,7 +323,7 @@ public void ReceiveSent_SmallSocketAddress_Throws() SocketAddress serverSA = server.LocalEndPoint.Serialize(); SocketAddress sa = new SocketAddress(AddressFamily.InterNetwork, 2); - Assert.Throws(() => server.ReceiveFrom(receiveBuffer, SocketFlags.None, sa)); + await Assert.ThrowsAsync(async () => await server.ReceiveFromAsync(receiveBuffer, SocketFlags.None, sa)); } [Theory] @@ -403,23 +413,26 @@ public async Task ShutdownSend_ReceiveFromShouldSucceed() using var sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); sender.BindToAnonymousPort(IPAddress.Loopback); - sender.SendTo(new byte[1], receiver.LocalEndPoint); + await sender.SendToAsync(new byte[1], receiver.LocalEndPoint); var r = await ReceiveFromAsync(receiver, new byte[1], sender.LocalEndPoint); Assert.Equal(1, r.ReceivedBytes); } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveFrom_Sync : ReceiveFrom { public ReceiveFrom_Sync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveFrom_SyncForceNonBlocking : ReceiveFrom { public ReceiveFrom_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveFrom_Apm : ReceiveFrom { public ReceiveFrom_Apm(ITestOutputHelper output) : base(output) { } @@ -463,7 +476,7 @@ public void EndReceiveFrom_AddressFamilyDoesNotMatch_Throws_ArgumentException() Assert.Throws("endPoint", () => socket.EndReceiveFrom(iar, ref invalidEndPoint)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [ActiveIssue("https://github.com/dotnet/runtime/issues/54418", TestPlatforms.MacCatalyst)] public void BeginReceiveFrom_RemoteEpIsReturnedWhenCompletedSynchronously() { @@ -532,11 +545,13 @@ public void ReceiveFromAsync_NullAsyncEventArgs_Throws_ArgumentNullException() } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveFrom_SpanSync : ReceiveFrom { public ReceiveFrom_SpanSync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveFrom_SpanSyncForceNonBlocking : ReceiveFrom { public ReceiveFrom_SpanSyncForceNonBlocking(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs index e8663bc8047e9d..d126a2dff21f24 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs @@ -87,6 +87,7 @@ public async Task NotBound_Throws_InvalidOperationException() [Theory] [InlineData(false)] [InlineData(true)] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task ReceiveSent_TCP_Success(bool ipv6) { if (ipv6 && PlatformDetection.IsApplePlatform) @@ -126,7 +127,7 @@ public async Task ReceiveSent_UDP_Success(bool ipv4) using Socket receiver = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); using Socket sender = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); - receiver.SetSocketOption(ipv4 ? SocketOptionLevel.IP : SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true); + if (!OperatingSystem.IsWasi()) receiver.SetSocketOption(ipv4 ? SocketOptionLevel.IP : SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true); ConfigureNonBlocking(sender); ConfigureNonBlocking(receiver); @@ -145,16 +146,19 @@ public async Task ReceiveSent_UDP_Success(bool ipv4) for (int i = 0; i < DatagramsToSend; i++) { rnd.NextBytes(sendBuffer); - sender.SendTo(sendBuffer, receiver.LocalEndPoint); + await sender.SendToAsync(sendBuffer, receiver.LocalEndPoint); SocketReceiveMessageFromResult result = await ReceiveMessageFromAsync(receiver, receiveBuffer, remoteEp); - IPPacketInformation packetInformation = result.PacketInformation; Assert.Equal(DatagramSize, result.ReceivedBytes); AssertExtensions.SequenceEqual(emptyBuffer, new ReadOnlySpan(receiveInternalBuffer, 0, Offset)); AssertExtensions.SequenceEqual(sendBuffer, new ReadOnlySpan(receiveInternalBuffer, Offset, DatagramSize)); Assert.Equal(sender.LocalEndPoint, result.RemoteEndPoint); - Assert.Equal(((IPEndPoint)sender.LocalEndPoint).Address, packetInformation.Address); + if (!OperatingSystem.IsWasi()) + { + IPPacketInformation packetInformation = result.PacketInformation; + Assert.Equal(((IPEndPoint)sender.LocalEndPoint).Address, packetInformation.Address); + } } } @@ -272,6 +276,7 @@ public async Task SendBroadcast_BroadcastFlagIsSetOnReceive() [Fact] [PlatformSpecific(TestPlatforms.AnyUnix)] // Windows doesn't report MSG_TRUNC + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support MSG_TRUNC")] public async Task ReceiveTruncated_TruncatedFlagIsSetOnReceive() { using var receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); @@ -285,16 +290,19 @@ public async Task ReceiveTruncated_TruncatedFlagIsSetOnReceive() } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveMessageFrom_Sync : ReceiveMessageFrom { public ReceiveMessageFrom_Sync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveMessageFrom_SyncForceNonBlocking : ReceiveMessageFrom { public ReceiveMessageFrom_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveMessageFrom_Apm : ReceiveMessageFrom { public ReceiveMessageFrom_Apm(ITestOutputHelper output) : base(output) { } @@ -345,7 +353,7 @@ public void EndReceiveMessageFrom_AddressFamilyDoesNotMatch_Throws_ArgumentExcep Assert.Throws("endPoint", () => socket.EndReceiveMessageFrom(iar, ref socketFlags, ref invalidEndPoint, out _)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void BeginReceiveMessageFrom_RemoteEpIsReturnedWhenCompletedSynchronously() { EndPoint anyEp = new IPEndPoint(IPAddress.Any, 0); @@ -412,7 +420,7 @@ public void ReceiveFromAsync_NullAsyncEventArgs_Throws_ArgumentNullException() Assert.Throws(() => socket.ReceiveMessageFromAsync(null)); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false, 0)] [InlineData(false, 1)] [InlineData(false, 2)] @@ -493,11 +501,13 @@ public void ReceiveSentMessages_ReuseEventArgs_Success(bool ipv4, int bufferMode } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveMessageFrom_SpanSync : ReceiveMessageFrom { public ReceiveMessageFrom_SpanSync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class ReceiveMessageFrom_SpanSyncForceNonBlocking : ReceiveMessageFrom { public ReceiveMessageFrom_SpanSyncForceNonBlocking(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SafeHandleTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SafeHandleTest.cs index 36b594654f7442..9e1453a1a7fa2e 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SafeHandleTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SafeHandleTest.cs @@ -18,7 +18,7 @@ public static void SafeHandle_NotIsInvalid() } [Fact] - [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.AnyUnix)] + [PlatformSpecific(TestPlatforms.Windows | TestPlatforms.AnyUnix ^ TestPlatforms.Wasi)] public void SafeSocketHandle_CanUseInPInvoke() { const int AF_INET = 2; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectAndPollTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectAndPollTests.cs index ff545111021418..a0bc4ed573441b 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectAndPollTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectAndPollTests.cs @@ -9,6 +9,7 @@ namespace System.Net.Sockets.Tests { + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class SelectAndPollTests { private const int SelectTimeout = 100; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectTest.cs index 190a688475339c..0e7d6649bdf814 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SelectTest.cs @@ -11,6 +11,7 @@ namespace System.Net.Sockets.Tests { + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class SelectTest { private readonly ITestOutputHelper _log; @@ -353,6 +354,7 @@ private static void DisposeSockets(IEnumerable> soc } [Collection(nameof(DisableParallelization))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class SelectTest_NonParallel { [OuterLoop] @@ -420,6 +422,7 @@ private static void DoAccept(Socket listenSocket, int connectionsToAccept) } [Collection(nameof(DisableParallelization))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] // Set of tests to not run together with any other tests. public class NoParallelSelectTests { diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index 5cc59d332f4ddf..10313336876ce4 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -74,7 +74,7 @@ public async Task UdpConnection_ThrowsException(bool usePreAndPostbufferOverload using var listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); listener.BindToAnonymousPort(IPAddress.Loopback); - client.Connect(listener.LocalEndPoint); + await client.ConnectAsync(listener.LocalEndPoint); if (usePreAndPostbufferOverload) { @@ -125,11 +125,11 @@ public async Task IncludeFile_Success(IPAddress listenAt, bool sendPreAndPostBuf int bytesReceived = 0; var receivedChecksum = new Fletcher32(); - var serverTask = Task.Run(() => + var serverTask = Task.Run(async () => { using (server) { - Socket remote = server.Accept(); + Socket remote = await server.AcceptAsync(); Assert.NotNull(remote); using (remote) @@ -176,11 +176,12 @@ public async Task NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) listener.BindToAnonymousPort(IPAddress.Loopback); listener.Listen(1); - client.Connect(listener.LocalEndPoint); - using Socket server = listener.Accept(); + await client.ConnectAsync(listener.LocalEndPoint); + using Socket server = await listener.AcceptAsync(); await SendFileAsync(server, null); - Assert.Equal(0, client.Available); + if (!OperatingSystem.IsWasi()) // https://github.com/WebAssembly/wasi-libc/issues/538 + Assert.Equal(0, client.Available); byte[] preBuffer = usePreBuffer ? new byte[1] : null; byte[] postBuffer = usePostBuffer ? new byte[1] : null; @@ -191,10 +192,11 @@ public async Task NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) byte[] receiveBuffer = new byte[1]; for (int i = 0; i < bytesExpected; i++) { - Assert.Equal(1, client.Receive(receiveBuffer)); + Assert.Equal(1, await client.ReceiveAsync(receiveBuffer)); } - Assert.Equal(0, client.Available); + if (!OperatingSystem.IsWasi()) // https://github.com/WebAssembly/wasi-libc/issues/538 + Assert.Equal(0, client.Available); } [Fact] @@ -361,31 +363,37 @@ private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_SyncSpan : SendFile { public SendFile_SyncSpan(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_SyncSpanForceNonBlocking : SendFile { public SendFile_SyncSpanForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_ArraySync : SendFile { public SendFile_ArraySync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_SyncForceNonBlocking : SendFile { public SendFile_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public sealed class SendFile_Task : SendFile { public SendFile_Task(ITestOutputHelper output) : base(output) { } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public sealed class SendFile_CancellableTask : SendFile { public SendFile_CancellableTask(ITestOutputHelper output) : base(output) { } @@ -445,6 +453,7 @@ public async Task SendFileAsync_CanceledDuringOperation_Throws(bool ipv6) } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_Apm : SendFile { public SendFile_Apm(ITestOutputHelper output) : base(output) { } @@ -515,26 +524,31 @@ public async Task GreaterThan2GBFile_SendsAllBytes() } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_NonParallel_SyncSpan : SendFile_NonParallel { public SendFile_NonParallel_SyncSpan(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_NonParallel_SyncSpanForceNonBlocking : SendFile_NonParallel { public SendFile_NonParallel_SyncSpanForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_NonParallel_ArraySync : SendFile_NonParallel { public SendFile_NonParallel_ArraySync(ITestOutputHelper output) : base(output) { } } + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public sealed class SendFile_NonParallel_Task : SendFile_NonParallel { public SendFile_NonParallel_Task(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendFile_NonParallel_Apm : SendFile_NonParallel { public SendFile_NonParallel_Apm(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs index 79d05dc28bde57..4aefa65406d7c0 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsAsync.cs @@ -14,6 +14,7 @@ namespace System.Net.Sockets.Tests { [Collection(nameof(DisableParallelization))] + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class SendPacketsAsync : IDisposable { private readonly ITestOutputHelper _log; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsElementTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsElementTest.cs index d0e1b33cf517b8..1c791e67c99ac2 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsElementTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendPacketsElementTest.cs @@ -618,6 +618,7 @@ public void FileStreamCtorNull_Throws() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public void FileStreamCtorNormal_Success() { using (var stream = File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) @@ -635,6 +636,7 @@ public void FileStreamCtorNormal_Success() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public void FileStreamCtorZeroCountLength_Success() { using (var stream = File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) @@ -662,6 +664,7 @@ public void FileStreamCtorZeroCountLength_Success() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public void FileStreamCtorNegOffset_ArgumentOutOfRangeException() { using (var stream = File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) @@ -686,6 +689,7 @@ public void FileStreamCtorNegOffset_ArgumentOutOfRangeException() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public void FileStreamCtorNegCount_ArgumentOutOfRangeException() { using (var stream = File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) @@ -710,6 +714,7 @@ public void FileStreamCtorNegCount_ArgumentOutOfRangeException() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public void FileStreamCtorSynchronous_ArgumentException() { using (var stream = File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose)) @@ -724,6 +729,7 @@ public void FileStreamCtorSynchronous_ArgumentException() // File lengths are validated on send [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public void FileStreamCtorEndOfBufferTrue_Success() { using (var stream = File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) @@ -764,6 +770,7 @@ public void FileStreamCtorEndOfBufferTrue_Success() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/85690", TestPlatforms.Wasi)] public void FileStreamCtorEndOfBufferFalse_Success() { using (var stream = File.Create(Path.GetTempFileName(), 4096, FileOptions.DeleteOnClose | FileOptions.Asynchronous)) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceive.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceive.cs index 209f91b2ffba95..ce7f48d90d30e1 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceive.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceive.cs @@ -156,7 +156,7 @@ await ConnectAsync(client, clientEndpoint) } } - client.LingerState = new LingerOption(true, LingerTime); + if (!OperatingSystem.IsWasi()) client.LingerState = new LingerOption(true, LingerTime); client.Shutdown(SocketShutdown.Send); await serverProcessingTask.WaitAsync(TestSettings.PassingTestTimeout).ConfigureAwait(false); } @@ -621,6 +621,7 @@ await Task.WhenAll( } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task SendRecv_0ByteReceive_Success() { using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) @@ -700,6 +701,7 @@ public async Task Send_0ByteSendTo_Success() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task Receive0ByteReturns_WhenPeerDisconnects() { using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) @@ -733,6 +735,7 @@ await Task.WhenAll( [Theory] [InlineData(false, 1)] [InlineData(true, 1)] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support Linger")] public async Task SendRecv_BlockingNonBlocking_LingerTimeout_Success(bool blocking, int lingerTimeout) { if (UsesSync) return; @@ -770,6 +773,7 @@ await Task.WhenAll( [Fact] [SkipOnPlatform(TestPlatforms.OSX | TestPlatforms.FreeBSD, "SendBufferSize, ReceiveBufferSize = 0 not supported on BSD like stacks.")] [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task SendRecv_NoBuffering_Success() { if (UsesSync) return; @@ -857,6 +861,7 @@ public void SocketSendReceiveBufferSize_SetZero_ThrowsSocketException() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task SendAsync_ConcurrentDispose_SucceedsOrThrowsAppropriateException() { if (UsesSync) return; @@ -895,6 +900,7 @@ error is SocketException || } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task ReceiveAsync_ConcurrentDispose_SucceedsOrThrowsAppropriateException() { if (UsesSync) return; @@ -946,6 +952,7 @@ error is SocketException || [Theory] [MemberData(nameof(UdpReceiveGetsCanceledByDispose_Data))] [SkipOnPlatform(TestPlatforms.OSX, "Not supported on OSX.")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] public async Task UdpReceiveGetsCanceledByDispose(IPAddress address, bool owning) { @@ -1023,6 +1030,7 @@ await Task.WhenAny(disposeTask, receiveTask) [Theory] [MemberData(nameof(TcpReceiveSendGetsCanceledByDispose_Data))] [ActiveIssue("https://github.com/dotnet/runtime/issues/50568", TestPlatforms.Android | TestPlatforms.LinuxBionic)] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task TcpReceiveSendGetsCanceledByDispose(bool receiveOrSend, bool ipv6Server, bool dualModeClient, bool owning) { // Aborting sync operations for non-owning handles is not supported on Unix. @@ -1145,6 +1153,7 @@ await socketOperation } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task TcpPeerReceivesFinOnShutdownWithPendingData() { // We try this a couple of times to deal with a timing race: if the Dispose happens @@ -1181,12 +1190,14 @@ await RetryHelper.ExecuteAsync(async () => } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceive_Sync : SendReceive { public SendReceive_Sync(ITestOutputHelper output) : base(output) { } [OuterLoop] [ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task BlockingRead_DoesntRequireAnotherThreadPoolThread() { await RemoteExecutor.Invoke(() => @@ -1236,11 +1247,13 @@ select Task.Factory.StartNew(() => pair.Item1.Receive(new byte[1]), Cancellation } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceive_SyncForceNonBlocking : SendReceive { public SendReceive_SyncForceNonBlocking(ITestOutputHelper output) : base(output) {} } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceive_Apm : SendReceive { public SendReceive_Apm(ITestOutputHelper output) : base(output) {} @@ -1256,6 +1269,7 @@ public sealed class SendReceive_Eap : SendReceive public SendReceive_Eap(ITestOutputHelper output) : base(output) {} } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceive_SpanSync : SendReceive { public SendReceive_SpanSync(ITestOutputHelper output) : base(output) { } @@ -1305,10 +1319,10 @@ public async Task Send_0ByteSendTo_Span_Success() for (int i = 0; i < 3; i++) { // Send empty packet then real data. - int bytesSent = client.SendTo(ReadOnlySpan.Empty, server.LocalEndPoint!); + int bytesSent = await client.SendToAsync(ArraySegment.Empty, server.LocalEndPoint!); Assert.Equal(0, bytesSent); - client.SendTo(new byte[] { 99 }, server.LocalEndPoint); + await client.SendToAsync(new byte[] { 99 }, server.LocalEndPoint); // Read empty packet byte[] buffer = new byte[10]; @@ -1329,6 +1343,7 @@ public async Task Send_0ByteSendTo_Span_Success() } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceive_SpanSyncForceNonBlocking : SendReceive { public SendReceive_SpanSyncForceNonBlocking(ITestOutputHelper output) : base(output) { } @@ -1431,6 +1446,7 @@ public async Task Precanceled_Throws() [Theory] [InlineData(false)] [InlineData(true)] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task SendAsync_CanceledDuringOperation_Throws(bool ipv6) { const int CancelAfter = 200; // ms @@ -1465,6 +1481,7 @@ public async Task SendAsync_CanceledDuringOperation_Throws(bool ipv6) [Theory] [InlineData(false)] [InlineData(true)] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support PortBlocker")] public async Task ReceiveAsync_CanceledDuringOperation_Throws(bool ipv6) { (Socket client, Socket server) = SocketTestExtensions.CreateConnectedSocketPair(ipv6); @@ -1487,6 +1504,7 @@ public async Task ReceiveAsync_CanceledDuringOperation_Throws(bool ipv6) } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task CanceledOneOfMultipleReceives_Udp_Throws() { using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) @@ -1544,7 +1562,7 @@ public async Task DisposedSocket_ThrowsOperationCanceledException() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task BlockingAsyncContinuations_OperationsStillCompleteSuccessfully() { if (UsesSync) return; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveMisc.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveMisc.cs index 44fe8a3b2cfff3..271c5d68896bec 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveMisc.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveMisc.cs @@ -10,7 +10,7 @@ namespace System.Net.Sockets.Tests { public class SendReceiveMisc { - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void SendRecvIovMaxTcp_Success() { // sending/receiving more than IOV_MAX segments causes EMSGSIZE on some platforms. @@ -76,7 +76,7 @@ public void SendRecvIovMaxTcp_Success() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void SendIovMaxUdp_SuccessOrMessageSize() { // sending more than IOV_MAX segments causes EMSGSIZE on some platforms. @@ -117,7 +117,7 @@ public void SendIovMaxUdp_SuccessOrMessageSize() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task ReceiveIovMaxUdp_SuccessOrMessageSize() { // receiving more than IOV_MAX segments causes EMSGSIZE on some platforms. @@ -190,7 +190,7 @@ public async Task ReceiveIovMaxUdp_SuccessOrMessageSize() await receiveTask; } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [SkipOnPlatform(TestPlatforms.Windows, "All data is sent, even when very large (100M).")] public void SocketSendWouldBlock_ReturnsBytesSent() { @@ -219,7 +219,7 @@ public void SocketSendWouldBlock_ReturnsBytesSent() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [PlatformSpecific(TestPlatforms.AnyUnix)] public async Task Socket_ReceiveFlags_Success() { @@ -284,7 +284,7 @@ public async Task Socket_ReceiveFlags_Success() } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(true)] [InlineData(false)] public void ReceiveFrom_MultipleRounds_Success(bool async) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveNonParallel.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveNonParallel.cs index 97cad8577407b2..20f1983f52e67f 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveNonParallel.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveNonParallel.cs @@ -104,16 +104,19 @@ public async Task SendToRecvFrom_Datagram_UDP(IPAddress loopbackAddress, bool us } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceiveNonParallel_Sync : SendReceiveNonParallel { public SendReceiveNonParallel_Sync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceiveNonParallel_SyncForceNonBlocking : SendReceiveNonParallel { public SendReceiveNonParallel_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceiveNonParallel_Apm : SendReceiveNonParallel { public SendReceiveNonParallel_Apm(ITestOutputHelper output) : base(output) { } @@ -134,11 +137,13 @@ public sealed class SendReceiveNonParallel_Eap : SendReceiveNonParallel { public SendReceiveNonParallel_SpanSync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendReceiveNonParallel_SpanSyncForceNonBlocking : SendReceiveNonParallel { public SendReceiveNonParallel_SpanSyncForceNonBlocking(ITestOutputHelper output) : base(output) { } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveUdpClient.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveUdpClient.cs index 252b862bce1abd..851ba978ebca65 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveUdpClient.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendReceive/SendReceiveUdpClient.cs @@ -10,7 +10,7 @@ namespace System.Net.Sockets.Tests public sealed class SendReceiveUdpClient : MemberDatas { [OuterLoop] - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [MemberData(nameof(LoopbacksAndUseMemory))] public async Task SendToRecvFromAsync_Datagram_UDP_UdpClient(IPAddress loopbackAddress, bool useMemoryOverload) { diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs index 7a3c33b64bf796..62598f6be434cc 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs @@ -69,7 +69,7 @@ public async Task NullSocketAddress_Throws_ArgumentException() using Socket socket = CreateSocket(); SocketAddress socketAddress = null; - Assert.Throws(() => socket.SendTo(new byte[1], SocketFlags.None, socketAddress)); + if (!OperatingSystem.IsWasi()) Assert.Throws(() => socket.SendTo(new byte[1], SocketFlags.None, socketAddress)); await AssertThrowsSynchronously(() => socket.SendToAsync(new byte[1], SocketFlags.None, socketAddress).AsTask()); } @@ -116,26 +116,31 @@ public async Task Disposed_Throws() } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendTo_SyncSpan : SendTo { public SendTo_SyncSpan(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendTo_SyncSpanForceNonBlocking : SendTo { public SendTo_SyncSpanForceNonBlocking(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendTo_ArraySync : SendTo { public SendTo_ArraySync(ITestOutputHelper output) : base(output) { } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendTo_SyncForceNonBlocking : SendTo { public SendTo_SyncForceNonBlocking(ITestOutputHelper output) : base(output) {} } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public sealed class SendTo_Apm : SendTo { public SendTo_Apm(ITestOutputHelper output) : base(output) {} diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Shutdown.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Shutdown.cs index 3f5a2003d9e348..00022fd6126782 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Shutdown.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Shutdown.cs @@ -71,7 +71,7 @@ private static void OnOperationCompleted(object sender, SocketAsyncEventArgs arg } [OuterLoop] // Explicitly waits for 5 seconds - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Shutdown_TCP_CLOSED_Success() { // NOTE: this value should technically be at least as long as the amount diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs index afd56dfcc9ef76..2a155776f3d157 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs @@ -72,6 +72,7 @@ public void Dispose_MultipleCalls_Success() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task Dispose_WhileInUse_DisposeDelayed() { using (var listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) @@ -105,7 +106,7 @@ await Task.WhenAll( } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public async Task ExecutionContext_FlowsIfNotSuppressed(bool suppressed) @@ -147,13 +148,13 @@ await Task.WhenAll( } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task ExecutionContext_SocketAsyncEventArgs_Ctor_Default_FlowIsNotSuppressed() { await ExecutionContext_SocketAsyncEventArgs_Ctors(() => new SocketAsyncEventArgs(), false); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(true)] [InlineData(false)] public async Task ExecutionContext_SocketAsyncEventArgs_Ctor_UnsafeSuppressExecutionContextFlow(bool suppressed) @@ -358,7 +359,7 @@ await Task.WhenAll( tcs2 = new TaskCompletionSource(); Assert.True(client.ReceiveAsync(receiveSaea)); - server.Send(new byte[1]); + await server.SendAsync(new byte[1]); await Task.WhenAll(tcs1.Task, tcs2.Task); receiveSaea.Completed -= handler2; @@ -367,7 +368,7 @@ await Task.WhenAll( tcs2 = new TaskCompletionSource(); Assert.True(client.ReceiveAsync(receiveSaea)); - server.Send(new byte[1]); + await server.SendAsync(new byte[1]); await tcs1.Task; Assert.False(tcs2.Task.IsCompleted); @@ -430,6 +431,7 @@ public void CancelConnectAsync_StaticConnect_CancelsInProgressConnect() [InlineData(false, 10_000)] [InlineData(true, 1)] // This should fit with SYN flag [InlineData(true, 10_000)] // This should be too big to fit completely to first packet. + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support FastOpen")] public async Task ConnectAsync_WithData_OK(bool useFastOpen, int size) { if (useFastOpen && PlatformDetection.IsWindows && !PlatformDetection.IsWindows10OrLater) @@ -521,7 +523,7 @@ public async Task ConnectAsync_WithData_OK(bool useFastOpen, int size) } } - [ConditionalTheory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false, 1)] [InlineData(false, 10_000)] [InlineData(true, 1)] // This should fit with SYN flag @@ -570,6 +572,7 @@ public async Task Connect_WithData_OK(bool useFastOpen, int size) } [Fact] + // [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ReuseSocketAsyncEventArgs_SameInstance_MultipleSockets() { using (var listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) @@ -687,7 +690,7 @@ private static void OnAcceptCompleted(object sender, SocketAsyncEventArgs args) } [OuterLoop] - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [PlatformSpecific(TestPlatforms.Windows)] // Unix platforms don't yet support receiving data with AcceptAsync. public void AcceptAsync_WithReceiveBuffer_Success() { @@ -775,6 +778,7 @@ public void AcceptAsync_WithReceiveBuffer_Failure() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task SocketConnectAsync_IPAddressAny_SocketAsyncEventArgsReusableAfterFailure() { var e = new SocketAsyncEventArgs(); @@ -1041,7 +1045,7 @@ void CreateSocketAsyncEventArgs() // separated out so that JIT doesn't extend li }, 30_000)); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public async Task SendTo_DifferentEP_Success(bool ipv4) @@ -1093,6 +1097,8 @@ internal static class ConnectExtensions { internal static void Connect(this Socket socket, EndPoint ep, Memory buffer, int timeout) { + Assert.False(OperatingSystem.IsWasi()); // wait below requires threading + var re = new ManualResetEventSlim(); var saea = new SocketAsyncEventArgs(); saea.SetBuffer(buffer); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs index 4ff0052bffb06a..58db131e2476d3 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketDuplicationTests.cs @@ -387,10 +387,12 @@ static async Task HandlerServerCode(string ipcPortString) } } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class Synchronous : PolymorphicTests { } + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class Apm : PolymorphicTests { } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs index 26752dd31f5dcb..8962f6b128e041 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketOptionNameTest.cs @@ -12,6 +12,7 @@ namespace System.Net.Sockets.Tests { + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public partial class SocketOptionNameTest { private static bool SocketsReuseUnicastPortSupport => Capability.SocketsReuseUnicastPortSupport().HasValue; @@ -720,6 +721,7 @@ public void SetUnsupportedRawSocketOption_DoesNotDisconnectSocket() [Collection(nameof(DisableParallelization))] // Set of tests to not run together with any other tests. + [ConditionalClass(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public class NoParallelTests { [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj index 2b5c1cea632f06..43844aea397681 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/System.Net.Sockets.Tests.csproj @@ -2,9 +2,10 @@ true true - $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser + $(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-browser;$(NetCoreAppCurrent)-wasi true true + true diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs index 6a86b2c5fabf92..a59e888fc33df7 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs @@ -38,7 +38,7 @@ public void Ctor_InvalidArguments_Throws() AssertExtensions.Throws("port", () => new TcpClient("localhost", -1)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Connect_InvalidArguments_Throws() { using (var client = new TcpClient()) @@ -53,6 +53,21 @@ public void Connect_InvalidArguments_Throws() } } + [Fact] + public async Task ConnectAsync_InvalidArguments_Throws() + { + using (var client = new TcpClient()) + { + await AssertExtensions.ThrowsAsync("host", () => client.ConnectAsync((string)null, 0)); + await AssertExtensions.ThrowsAsync("port", () => client.ConnectAsync("localhost", -1)); + + await AssertExtensions.ThrowsAsync("address", () => client.ConnectAsync((IPAddress)null, 0)); + await AssertExtensions.ThrowsAsync("port", () => client.ConnectAsync(IPAddress.Loopback, -1)); + + await AssertExtensions.ThrowsAsync("remoteEP", () => client.ConnectAsync(null)); + } + } + [Fact] public void GetStream_NotConnected_Throws() { @@ -62,7 +77,7 @@ public void GetStream_NotConnected_Throws() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Active_Roundtrips() { using (var client = new DerivedTcpClient()) @@ -78,7 +93,7 @@ public void Active_Roundtrips() } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public void DisposeClose_OperationsThrow(bool close) @@ -198,7 +213,7 @@ public async Task ConnectAsync_DnsEndPoint_Success(int mode) } [OuterLoop] - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(0)] [InlineData(1)] [InlineData(2)] @@ -272,6 +287,7 @@ public void ConnectedAvailable_NullClient() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] public void Roundtrip_ExclusiveAddressUse_GetEqualsSet_True() { using (TcpClient client = new TcpClient()) @@ -454,7 +470,7 @@ public async Task Dispose_CancelsConnectAsync(bool connectByName) } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Connect_Dual_Success() { if (!Socket.OSSupportsIPv6) @@ -481,7 +497,7 @@ public void Connect_Dual_Success() } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false, "::ffff:127.0.0.1")] [InlineData(false, "127.0.0.1")] [InlineData(false, "localhost")] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs index 2e47f057a8d8c0..2611feb416134a 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs @@ -101,7 +101,7 @@ public void Start_InvalidArgs_Throws() listener.Stop(); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task Pending_TrueWhenWaitingRequest() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -120,7 +120,7 @@ public async Task Pending_TrueWhenWaitingRequest() Assert.Throws(() => listener.Pending()); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Accept_Invalid_Throws() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -145,8 +145,15 @@ public void Accept_Invalid_Throws() [InlineData(2)] // Async with Cancellation [InlineData(3)] // APM [ActiveIssue("https://github.com/dotnet/runtime/issues/51392", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task Accept_AcceptsPendingSocketOrClient(int mode) { + if (OperatingSystem.IsWasi() && (mode == 0 || mode == 3)) + { + // Sync and APM are not supported on WASI + return; + } + var listener = new TcpListener(IPAddress.Loopback, 0); listener.Start(); @@ -204,6 +211,7 @@ public void IPv6_Only_Works() } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task Accept_StartAfterStop_AcceptsSuccessfully() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -229,6 +237,7 @@ async Task VerifyAccept(TcpListener listener) } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] public void ExclusiveAddressUse_ListenerNotStarted_SetAndReadSuccessfully() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -240,6 +249,7 @@ public void ExclusiveAddressUse_ListenerNotStarted_SetAndReadSuccessfully() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] public void ExclusiveAddressUse_SetStartListenerThenRead_ReadSuccessfully() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -254,6 +264,7 @@ public void ExclusiveAddressUse_SetStartListenerThenRead_ReadSuccessfully() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] public void ExclusiveAddressUse_SetStartAndStopListenerThenRead_ReadSuccessfully() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -271,7 +282,7 @@ public void ExclusiveAddressUse_SetStartAndStopListenerThenRead_ReadSuccessfully Assert.True(listener.ExclusiveAddressUse); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void EndAcceptSocket_WhenStopped_ThrowsObjectDisposedException() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -286,7 +297,7 @@ public void EndAcceptSocket_WhenStopped_ThrowsObjectDisposedException() Assert.Throws(() => listener.EndAcceptSocket(iar)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void EndAcceptTcpClient_WhenStopped_ThrowsObjectDisposedException() { var listener = new TcpListener(IPAddress.Loopback, 0); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs index a57d61c110707f..e9ed5a2e1fe456 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs @@ -60,9 +60,9 @@ public static void EventSource_ExistsWithCorrectId() public static IEnumerable SocketMethods_MemberData() { - yield return new[] { "Sync" }; + if (!OperatingSystem.IsWasi()) yield return new[] { "Sync" }; yield return new[] { "Task" }; - yield return new[] { "Apm" }; + if (!OperatingSystem.IsWasi()) yield return new[] { "Apm" }; yield return new[] { "Eap" }; } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TimeoutTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TimeoutTest.cs index a442af692e5a70..60cadec1d802d4 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TimeoutTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TimeoutTest.cs @@ -7,6 +7,7 @@ namespace System.Net.Sockets.Tests { [Collection(nameof(DisableParallelization))] + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support Timeout yet")] // see https://github.com/WebAssembly/wasi-libc/issues/539 public class TimeoutTest { [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs index 4b8db5e71d6d2f..278ff346b4b352 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs @@ -60,7 +60,7 @@ public void Ctor_NullEndpoint_Throws() AssertExtensions.Throws("localEP", () => new UdpClient(null)); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Ctor_CanSend() { using (var udpClient = new DerivedUdpClient()) @@ -71,6 +71,16 @@ public void Ctor_CanSend() } [Fact] + public async Task Ctor_CanSendAsync() + { + using (var udpClient = new DerivedUdpClient()) + { + Assert.Equal(1, await udpClient.SendAsync(new byte[1], 1, new IPEndPoint(IPAddress.Loopback, UnusedPort))); + Assert.False(udpClient.Active); + } + } + + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Ctor_Int_CanSend() { try @@ -87,7 +97,7 @@ public void Ctor_Int_CanSend() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Ctor_IntAddressFamily_IPv4_CanSend() { try @@ -104,7 +114,7 @@ public void Ctor_IntAddressFamily_IPv4_CanSend() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Ctor_IntAddressFamily_IPv6_CanSend() { try @@ -121,7 +131,7 @@ public void Ctor_IntAddressFamily_IPv6_CanSend() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Ctor_IPEndPoint_CanSend() { try @@ -138,7 +148,7 @@ public void Ctor_IPEndPoint_CanSend() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Ctor_StringInt_CanSend() { using (var udpClient = new DerivedUdpClient("localhost", UnusedPort)) @@ -148,7 +158,7 @@ public void Ctor_StringInt_CanSend() } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public void DisposeClose_OperationsThrow(bool close) @@ -267,6 +277,7 @@ public void Ttl_Roundtrips() [Fact] [ActiveIssue("https://github.com/dotnet/runtime/issues/51392", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + [SkipOnPlatform(TestPlatforms.Wasi, "Not supported on Wasi.")] public void DontFragment_Roundtrips() { using (var udpClient = new UdpClient()) @@ -282,6 +293,7 @@ public void DontFragment_Roundtrips() [Theory] [InlineData(AddressFamily.InterNetwork)] [InlineData(AddressFamily.InterNetworkV6)] + [SkipOnPlatform(TestPlatforms.Wasi, "Not supported on Wasi.")] public void MulticastLoopback_Roundtrips(AddressFamily addressFamily) { using (var udpClient = new UdpClient(addressFamily)) @@ -295,6 +307,7 @@ public void MulticastLoopback_Roundtrips(AddressFamily addressFamily) } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Not supported on Wasi.")] public void EnableBroadcast_Roundtrips() { using (var udpClient = new UdpClient()) @@ -321,7 +334,7 @@ public void ExclusiveAddressUse_Roundtrips() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void InvalidArguments_Throw() { using (var udpClient = new UdpClient("localhost", UnusedPort)) @@ -332,7 +345,7 @@ public void InvalidArguments_Throw() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void BeginSend_NegativeBytes_Throws() { using (UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork)) @@ -347,7 +360,7 @@ public void BeginSend_NegativeBytes_Throws() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void BeginSend_BytesMoreThanArrayLength_Throws() { using (UdpClient udpClient = new UdpClient(AddressFamily.InterNetwork)) @@ -362,7 +375,7 @@ public void BeginSend_BytesMoreThanArrayLength_Throws() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void BeginSend_AsyncOperationCompletes_Success() { using (UdpClient udpClient = new UdpClient()) @@ -376,7 +389,7 @@ public void BeginSend_AsyncOperationCompletes_Success() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Send_InvalidArguments_Throws() { using (var udpClient = new DerivedUdpClient()) @@ -389,6 +402,15 @@ public void Send_InvalidArguments_Throws() udpClient.Active = true; Assert.Throws(() => udpClient.Send(new byte[1], 1, new IPEndPoint(IPAddress.Loopback, 0))); Assert.Throws(() => udpClient.Send(new ReadOnlySpan(new byte[1]), new IPEndPoint(IPAddress.Loopback, 0))); + } + } + + [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] + public void SendAsync_InvalidArguments_Throws() + { + using (var udpClient = new DerivedUdpClient()) + { Assert.Throws(() => {udpClient.SendAsync(new byte[1], 1, new IPEndPoint(IPAddress.Loopback, 0));}); Assert.Throws(() => udpClient.SendAsync(new ReadOnlyMemory(new byte[1]), new IPEndPoint(IPAddress.Loopback, 0))); } @@ -423,7 +445,7 @@ public void Client_Idempotent() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Connect_InvalidArguments_Throws() { using (var udpClient = new UdpClient()) @@ -458,7 +480,7 @@ public async Task ConnectAsync_IPAddressHost_Success() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Connect_StringHost_Success() { using (var c = new UdpClient()) @@ -467,7 +489,7 @@ public void Connect_StringHost_Success() } } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public void Connect_IPAddressHost_Success() { using (var c = new UdpClient()) @@ -508,7 +530,7 @@ public void AllowNatTraversal_AnyUnix(bool allow) } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public void Send_Receive_Success(bool ipv4) @@ -572,7 +594,7 @@ private static void AssertReceive(UdpClient receiver, byte[] sentData) Assert.True(Enumerable.SequenceEqual(sentData, data)); } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public void Send_Available_Success(bool ipv4) @@ -588,7 +610,7 @@ public void Send_Available_Success(bool ipv4) } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public void BeginEndSend_BeginEndReceive_Success(bool ipv4) @@ -752,6 +774,7 @@ public async Task SendAsync_PreCanceled_Throws(bool ipv4) } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Not supported on Wasi.")] public void JoinDropMulticastGroup_InvalidArguments_Throws() { using (var udpClient = new UdpClient(AddressFamily.InterNetwork)) @@ -800,6 +823,7 @@ public void UdpReceiveResult_Equality() } [Fact] + [SkipOnPlatform(TestPlatforms.Wasi, "Not supported on Wasi.")] public void BeginSend_IPv6Socket_IPv4Dns_Success() { using (var receiver = new UdpClient("127.0.0.1", DiscardPort)) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs index a49b8aa235a4ee..7cb10777d81aa6 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UnixDomainSocketTest.cs @@ -15,6 +15,7 @@ namespace System.Net.Sockets.Tests { + [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support UnixDomainSocket")] public class UnixDomainSocketTest { private readonly ITestOutputHelper _log; diff --git a/src/libraries/tests.proj b/src/libraries/tests.proj index e0c341cc41e90b..02a004f4ed62f9 100644 --- a/src/libraries/tests.proj +++ b/src/libraries/tests.proj @@ -584,6 +584,7 @@ + diff --git a/src/mono/sample/wasi/sockets-p2/Program.cs b/src/mono/sample/wasi/sockets-p2/Program.cs new file mode 100644 index 00000000000000..c26cc8eb52e7e7 --- /dev/null +++ b/src/mono/sample/wasi/sockets-p2/Program.cs @@ -0,0 +1,61 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Net.Http.Headers; +using System.Net.Http; +using System.Threading.Tasks; +using System.Threading; +using System.Runtime.CompilerServices; +using System.Net; +using System.Net.Sockets; +using System.Text; + +public static class WasiMainWrapper +{ + public static async Task MainAsync(string[] args) + { + IPHostEntry ipHostInfo = await Dns.GetHostEntryAsync("example.com"); + IPAddress ipAddress = ipHostInfo.AddressList[0]; + Console.WriteLine($"IP Address: {ipAddress}"); + + IPEndPoint ipEndPoint = new(ipAddress, 80); + using Socket client = new(ipEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + + await client.ConnectAsync(ipEndPoint); + + // Send message. + var message = @"GET / HTTP/1.1 +Host: example.com +Accept: */* + +"; + var messageBytes = Encoding.UTF8.GetBytes(message); + var start = 0; + while (start < messageBytes.Length) + { + start += await client.SendAsync(messageBytes.AsMemory(start), SocketFlags.None); + Console.WriteLine("TODO poll here"); + } + Console.WriteLine("GET sent"); + + // Receive ack. + var buffer = new byte[2048]; + var received = await client.ReceiveAsync(buffer, SocketFlags.None); + var response = Encoding.UTF8.GetString(buffer, 0, received); + Console.WriteLine(response); + + client.Shutdown(SocketShutdown.Both); + + return 0; + } + + public static int Main(string[] args) + { + return PollWasiEventLoopUntilResolved((Thread)null!, MainAsync(args)); + + [UnsafeAccessor(UnsafeAccessorKind.StaticMethod, Name = "PollWasiEventLoopUntilResolved")] + static extern T PollWasiEventLoopUntilResolved(Thread t, Task mainTask); + } + +} diff --git a/src/mono/sample/wasi/sockets-p2/Wasip2.Sockets.Console.Sample.csproj b/src/mono/sample/wasi/sockets-p2/Wasip2.Sockets.Console.Sample.csproj new file mode 100644 index 00000000000000..9f14b7b45051c0 --- /dev/null +++ b/src/mono/sample/wasi/sockets-p2/Wasip2.Sockets.Console.Sample.csproj @@ -0,0 +1,13 @@ + + + $(NetCoreAppCurrent) + <_WasiNeedsHttp>true + <_WasiNeedsSocket>true + + + + + From 018b2511f07be0e07b9aaa56712ec8b8f1f1c311 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 24 Sep 2024 01:34:37 +0200 Subject: [PATCH 04/14] fix --- src/native/libs/System.Native/pal_networking.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c index 052bc7ede9d2ea..dcc5039e36a621 100644 --- a/src/native/libs/System.Native/pal_networking.c +++ b/src/native/libs/System.Native/pal_networking.c @@ -3363,6 +3363,8 @@ int32_t SystemNative_GetWasiSocketDescriptor(intptr_t socket, void** entry) #else int32_t SystemNative_GetWasiSocketDescriptor(intptr_t socket, void** entry) { + (void)socket; + (void)entry; return Error_ENOSYS; } #endif // TARGET_WASI From ed6fdcba2e41be536369221992dd69e426894697 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 24 Sep 2024 02:39:40 +0200 Subject: [PATCH 05/14] fix --- .../tests/FunctionalTests/LoggingTest.cs | 1 + .../tests/FunctionalTests/TelemetryTest.cs | 1 + .../tests/FunctionalTests/UdpClientTest.cs | 11 ----------- 3 files changed, 2 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LoggingTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LoggingTest.cs index d23ee70a0b4a88..69c44d3d443bdf 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LoggingTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LoggingTest.cs @@ -20,6 +20,7 @@ public LoggingTest(ITestOutputHelper output) } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public static void EventSource_ExistsWithCorrectId() { Type esType = typeof(Socket).Assembly.GetType("System.Net.NetEventSource", throwOnError: true, ignoreCase: false); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs index e9ed5a2e1fe456..69f61fc180a49c 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TelemetryTest.cs @@ -47,6 +47,7 @@ public TelemetryTest(ITestOutputHelper output) } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public static void EventSource_ExistsWithCorrectId() { Type esType = typeof(Socket).Assembly.GetType("System.Net.Sockets.SocketsTelemetry", throwOnError: true, ignoreCase: false); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs index 278ff346b4b352..cd5a209dfa5b4b 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/UdpClientTest.cs @@ -405,17 +405,6 @@ public void Send_InvalidArguments_Throws() } } - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] - public void SendAsync_InvalidArguments_Throws() - { - using (var udpClient = new DerivedUdpClient()) - { - Assert.Throws(() => {udpClient.SendAsync(new byte[1], 1, new IPEndPoint(IPAddress.Loopback, 0));}); - Assert.Throws(() => udpClient.SendAsync(new ReadOnlyMemory(new byte[1]), new IPEndPoint(IPAddress.Loopback, 0))); - } - } - [Fact] [PlatformSpecific(TestPlatforms.Windows)] // localhost on Windows resolves to both IPV4/6, but doesn't on all Unix public void Send_InvalidArguments_StringInt_Throws() From f2388357f1c612872c1912365f92d4688d39fb06 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Tue, 24 Sep 2024 16:46:29 +0200 Subject: [PATCH 06/14] make WASI accept SOCK_NONBLOCK --- .../System/IO/StreamConformanceTests.cs | 146 ++++++++++++------ .../FunctionalTests/NetworkStreamTest.cs | 8 +- .../libs/System.Native/pal_networking.c | 6 +- 3 files changed, 105 insertions(+), 55 deletions(-) diff --git a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs index c88f3e62235a69..441b88811d5baf 100644 --- a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs +++ b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs @@ -65,6 +65,31 @@ public abstract class StreamConformanceTests : FileCleanupTestBase protected virtual bool CanSetLength => CanSeek; protected virtual bool CanSetLengthGreaterThanCapacity => CanSetLength; + protected bool SkipOnWasi(ReadWriteMode mode) + { + if (!OperatingSystem.IsWasi()) return false; + switch (mode) + { + case ReadWriteMode.AsyncArray: + case ReadWriteMode.AsyncMemory: + return false; + case ReadWriteMode.SyncAPM: + case ReadWriteMode.AsyncAPM: + case ReadWriteMode.SyncByte: + case ReadWriteMode.SyncSpan: + case ReadWriteMode.SyncArray: + default: + return true; + } + } + + protected static byte[] GetRandomBytes(int count) + { + byte[] buffer = new byte[count]; + System.Random.Shared.NextBytes(buffer); + return buffer; + } + /// Specifies the form of the read/write operation to use. public enum ReadWriteMode { @@ -700,6 +725,7 @@ public abstract class StandaloneStreamConformanceTests : StreamConformanceTests } [Fact] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ArgumentValidation_ThrowsExpectedException() { await foreach (Stream? stream in GetStreamsForValidation()) @@ -742,6 +768,8 @@ public virtual async Task ReadWriteAsync_Precanceled_ThrowsOperationCanceledExce [MemberData(nameof(AllReadWriteModes))] public virtual async Task Read_NonEmptyStream_Nop_Success(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using Stream? stream = await CreateReadOnlyStream(new byte[10]); if (stream is null) { @@ -758,6 +786,8 @@ public virtual async Task Read_NonEmptyStream_Nop_Success(ReadWriteMode mode) [MemberData(nameof(AllReadWriteModes))] public virtual async Task Write_Nop_Success(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using Stream? stream = await CreateReadWriteStream(); if (stream is null) { @@ -777,8 +807,11 @@ public virtual async Task Write_Nop_Success(ReadWriteMode mode) [InlineData(ReadWriteMode.SyncArray)] [InlineData(ReadWriteMode.AsyncArray)] [InlineData(ReadWriteMode.AsyncAPM)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Read_DataStoredAtDesiredOffset(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + const byte Expected = 42; using Stream? stream = await CreateReadWriteStream(new byte[] { Expected }); @@ -802,8 +835,11 @@ public virtual async Task Read_DataStoredAtDesiredOffset(ReadWriteMode mode) [InlineData(ReadWriteMode.SyncArray)] [InlineData(ReadWriteMode.AsyncArray)] [InlineData(ReadWriteMode.AsyncAPM)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Write_DataReadFromDesiredOffset(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using Stream? stream = await CreateReadWriteStream(); if (stream is null) { @@ -821,6 +857,8 @@ public virtual async Task Write_DataReadFromDesiredOffset(ReadWriteMode mode) [MemberData(nameof(AllReadWriteModes))] public virtual async Task Read_EmptyStream_Nop_Success(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using Stream? stream = await CreateReadOnlyStream(); if (stream is null) { @@ -841,7 +879,9 @@ public virtual async Task Read_EmptyStream_Nop_Success(ReadWriteMode mode) [MemberData(nameof(AllReadWriteModesAndValue), 256)] public virtual async Task Read_PopulatedWithInitialData_KnownSize_Success(ReadWriteMode mode, int size) { - byte[] expected = RandomNumberGenerator.GetBytes(size); + if (SkipOnWasi(mode)) return; + + byte[] expected = GetRandomBytes(size); using Stream? stream = await CreateReadOnlyStream(expected); if (stream is null) @@ -872,7 +912,9 @@ public virtual async Task Read_PopulatedWithInitialData_KnownSize_Success(ReadWr [MemberData(nameof(AllReadWriteModesAndValue), 4097)] public virtual async Task Read_PopulatedWithInitialData_ToEof_Success(ReadWriteMode mode, int size) { - byte[] expected = RandomNumberGenerator.GetBytes(size); + if (SkipOnWasi(mode)) return; + + byte[] expected = GetRandomBytes(size); using Stream? stream = await CreateReadOnlyStream(expected); if (stream is null) @@ -904,7 +946,9 @@ public virtual async Task Read_PopulatedWithInitialData_ToEof_Success(ReadWriteM [MemberData(nameof(AllReadWriteModes))] public virtual async Task Read_PartiallySatisfied_RemainderOfBufferUntouched(ReadWriteMode mode) { - byte[] expected = RandomNumberGenerator.GetBytes(20); + if (SkipOnWasi(mode)) return; + + byte[] expected = GetRandomBytes(20); using Stream? stream = await CreateReadOnlyStream(expected); if (stream is null) @@ -935,7 +979,9 @@ public virtual async Task Read_PartiallySatisfied_RemainderOfBufferUntouched(Rea [InlineData(true)] public virtual async Task Read_CustomMemoryManager_Success(bool useAsync) { - byte[] expected = RandomNumberGenerator.GetBytes(20); + if (OperatingSystem.IsWasi() && !useAsync) return; + + byte[] expected = GetRandomBytes(20); using Stream? stream = await CreateReadOnlyStream(expected); if (stream is null) @@ -959,6 +1005,8 @@ await stream.ReadAsync(memoryManager.Memory) : [InlineData(true)] public virtual async Task Write_CustomMemoryManager_Success(bool useAsync) { + if (OperatingSystem.IsWasi() && !useAsync) return; + using Stream? stream = await CreateReadWriteStream(); if (stream is null) { @@ -967,7 +1015,7 @@ public virtual async Task Write_CustomMemoryManager_Success(bool useAsync) using MemoryManager memoryManager = new NativeMemoryManager(256); Assert.Equal(256, memoryManager.Memory.Length); - byte[] expected = RandomNumberGenerator.GetBytes(memoryManager.Memory.Length); + byte[] expected = GetRandomBytes(memoryManager.Memory.Length); expected.AsSpan().CopyTo(memoryManager.Memory.Span); if (useAsync) @@ -990,6 +1038,8 @@ public virtual async Task Write_CustomMemoryManager_Success(bool useAsync) public virtual async Task CopyTo_CopiesAllDataFromRightPosition_Success( bool useAsync, byte[] expected, int position) { + if (OperatingSystem.IsWasi() && !useAsync) return; + using Stream? stream = await CreateReadOnlyStream(expected); if (stream is null) { @@ -1029,7 +1079,7 @@ public virtual async Task CopyTo_CopiesAllDataFromRightPosition_Success( public static IEnumerable CopyTo_CopiesAllDataFromRightPosition_Success_MemberData() { - byte[] expected = RandomNumberGenerator.GetBytes(16 * 1024); + byte[] expected = GetRandomBytes(16 * 1024); foreach (bool useAsync in new[] { false, true }) { yield return new object[] { useAsync, expected, 0 }; // beginning @@ -1043,6 +1093,8 @@ public static IEnumerable CopyTo_CopiesAllDataFromRightPosition_Succes [MemberData(nameof(AllReadWriteModes))] public virtual async Task Write_Read_Success(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + const int Length = 1024; using Stream? stream = await CreateReadWriteStream(); @@ -1051,7 +1103,7 @@ public virtual async Task Write_Read_Success(ReadWriteMode mode) return; } - byte[] expected = RandomNumberGenerator.GetBytes(Length); + byte[] expected = GetRandomBytes(Length); const int Copies = 3; for (int i = 0; i < Copies; i++) @@ -1074,6 +1126,8 @@ public virtual async Task Write_Read_Success(ReadWriteMode mode) [MemberData(nameof(AllReadWriteModes))] public virtual async Task Flush_ReadOnly_DoesntImpactReading(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using Stream? stream = await CreateReadOnlyStream(new byte[] { 0, 1, 2, 3, 4, 5 }); if (stream is null) { @@ -1094,6 +1148,8 @@ public virtual async Task Flush_ReadOnly_DoesntImpactReading(ReadWriteMode mode) [InlineData(ReadWriteMode.AsyncArray)] public virtual async Task Flush_MultipleTimes_Idempotent(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using Stream? stream = await CreateReadWriteStream(); if (stream is null) { @@ -1119,7 +1175,7 @@ public virtual async Task Flush_MultipleTimes_Idempotent(ReadWriteMode mode) await FlushAsync(mode, stream); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public virtual async Task Flush_SetLengthAtEndOfBuffer_OperatesOnValidData() { if (!CanSeek || !CanSetLengthGreaterThanCapacity) @@ -1225,7 +1281,7 @@ public virtual async Task Seek_RandomWalk_ReadConsistency() const int MaxBytesToRead = 21; // Write data to the file - byte[] buffer = RandomNumberGenerator.GetBytes(FileLength); + byte[] buffer = GetRandomBytes(FileLength); stream.Write(buffer, 0, buffer.Length); Assert.Equal(buffer.Length, stream.Position); Assert.Equal(buffer.Length, stream.Length); @@ -1267,7 +1323,7 @@ public virtual async Task Seek_Read_RoundtripsExpectedData(SeekMode mode) const int Length = 512; - byte[] expected = RandomNumberGenerator.GetBytes(Length); + byte[] expected = GetRandomBytes(Length); using Stream? stream = await CreateReadOnlyStream(expected); if (stream is null) { @@ -1293,7 +1349,7 @@ public virtual async Task Seek_PastEnd_ReadReturns0(SeekMode mode) const int Length = 512; - byte[] expected = RandomNumberGenerator.GetBytes(Length); + byte[] expected = GetRandomBytes(Length); using Stream? stream = await CreateReadOnlyStream(expected); if (stream is null) { @@ -1318,7 +1374,7 @@ public virtual async Task Seek_ReadWrite_RoundtripsExpectedData(SeekMode mode) const int Length = 512; - byte[] expected = RandomNumberGenerator.GetBytes(Length); + byte[] expected = GetRandomBytes(Length); using Stream? stream = await CreateReadWriteStream(expected); if (stream is null) { @@ -1442,6 +1498,8 @@ public virtual async Task SetLength_ChangesLengthAccordingly_Success() [MemberData(nameof(AllReadWriteModes))] public virtual async Task SetLength_DataFromShrinkNotPreserved_Success(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + if (!CanSeek || !CanSetLength) { return; @@ -1514,6 +1572,8 @@ public async Task SetLength_MaxValue_ThrowsExpectedException() [MemberData(nameof(AllReadWriteModes))] public virtual async Task SeekPastEnd_Write_BeyondCapacity(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + if (!CanSeek) { return; @@ -1527,7 +1587,7 @@ public virtual async Task SeekPastEnd_Write_BeyondCapacity(ReadWriteMode mode) long origLength = stream.Length; - byte[] expected = RandomNumberGenerator.GetBytes(10); + byte[] expected = GetRandomBytes(10); // Move past end; doesn't change stream length. int pastEnd = 5; @@ -1626,7 +1686,6 @@ public virtual async Task ArgumentValidation_ThrowsExpectedException() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Disposed_ThrowsObjectDisposedException() { StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1641,7 +1700,6 @@ public virtual async Task Disposed_ThrowsObjectDisposedException() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWriteAsync_PrecanceledOperations_ThrowsCancellationException() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1657,7 +1715,6 @@ public virtual async Task ReadWriteAsync_PrecanceledOperations_ThrowsCancellatio [InlineData(100)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_CancelPendingTask_ThrowsCancellationException(int cancellationDelay) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1671,7 +1728,6 @@ public virtual async Task ReadAsync_CancelPendingTask_ThrowsCancellationExceptio [InlineData(100)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_CancelPendingValueTask_ThrowsCancellationException(int cancellationDelay) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1680,17 +1736,16 @@ public virtual async Task ReadAsync_CancelPendingValueTask_ThrowsCancellationExc await ValidateCancelableReadAsyncValueTask_AfterInvocation_ThrowsCancellationException(readable, cancellationDelay); } - [Fact] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWriteByte_Success() { using StreamPair streams = await CreateConnectedStreamsAsync(); foreach ((Stream writeable, Stream readable) in GetReadWritePairs(streams)) { - byte[] writerBytes = RandomNumberGenerator.GetBytes(42); + byte[] writerBytes = GetRandomBytes(42); var readerBytes = new byte[writerBytes.Length]; Task writes = Task.Run(() => @@ -1759,9 +1814,10 @@ public virtual async Task ReadWrite_Success_Large(ReadWriteMode mode, int writeS [MemberData(nameof(ReadWrite_Success_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_Success(ReadWriteMode mode, int writeSize, bool startWithFlush) { + if (SkipOnWasi(mode)) return; + foreach (CancellationToken nonCanceledToken in new[] { CancellationToken.None, new CancellationTokenSource().Token }) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -1773,7 +1829,7 @@ public virtual async Task ReadWrite_Success(ReadWriteMode mode, int writeSize, b await FlushAsync(mode, writeable, nonCanceledToken); } - byte[] writerBytes = RandomNumberGenerator.GetBytes(writeSize); + byte[] writerBytes = GetRandomBytes(writeSize); var readerBytes = new byte[writerBytes.Length]; Task writes = Task.Run(async () => @@ -1818,9 +1874,10 @@ public virtual async Task ReadWrite_Success(ReadWriteMode mode, int writeSize, b [MemberData(nameof(ReadWrite_Modes))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_MessagesSmallerThanReadBuffer_Success(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + if (!FlushGuaranteesAllDataWritten) { return; @@ -1832,7 +1889,7 @@ public virtual async Task ReadWrite_MessagesSmallerThanReadBuffer_Success(ReadWr foreach ((Stream writeable, Stream readable) in GetReadWritePairs(streams)) { - byte[] writerBytes = RandomNumberGenerator.GetBytes(512); + byte[] writerBytes = GetRandomBytes(512); var readerBytes = new byte[writerBytes.Length * 2]; // Repeatedly write then read a message smaller in size than the read buffer @@ -1864,14 +1921,15 @@ public virtual async Task ReadWrite_MessagesSmallerThanReadBuffer_Success(ReadWr } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [MemberData(nameof(AllReadWriteModesAndValue), false)] [MemberData(nameof(AllReadWriteModesAndValue), true)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Read_Eof_Returns0(ReadWriteMode mode, bool dataAvailableFirst) { + if (SkipOnWasi(mode)) return; + using StreamPair streams = await CreateConnectedStreamsAsync(); (Stream writeable, Stream readable) = GetReadWritePair(streams); @@ -1913,6 +1971,8 @@ public virtual async Task Read_Eof_Returns0(ReadWriteMode mode, bool dataAvailab [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Read_DataStoredAtDesiredOffset(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using StreamPair streams = await CreateConnectedStreamsAsync(); (Stream writeable, Stream readable) = GetReadWritePair(streams); @@ -1945,6 +2005,8 @@ public virtual async Task Read_DataStoredAtDesiredOffset(ReadWriteMode mode) [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Write_DataReadFromDesiredOffset(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using StreamPair streams = await CreateConnectedStreamsAsync(); (Stream writeable, Stream readable) = GetReadWritePair(streams); @@ -1988,7 +2050,6 @@ public virtual async Task WriteWithBrokenPipe_Throws() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_NonReusableValueTask_AwaitMultipleTimes_Throws() { if (!ReadWriteValueTasksProtectSingleConsumption) @@ -2018,7 +2079,6 @@ public virtual async Task ReadAsync_NonReusableValueTask_AwaitMultipleTimes_Thro } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_NonReusableValueTask_MultipleContinuations_Throws() { if (!ReadWriteValueTasksProtectSingleConsumption) @@ -2045,7 +2105,6 @@ public static IEnumerable ReadAsync_ContinuesOnCurrentContextIfDesired [MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_ContinuesOnCurrentSynchronizationContextIfDesired(bool flowExecutionContext, bool? continueOnCapturedContext) { using StreamPair streams = await CreateConnectedStreamsAsync().ConfigureAwait(ConfigureAwaitOptions.ForceYielding /* escape xunit sync ctx */); @@ -2128,7 +2187,6 @@ public virtual async Task ReadAsync_ContinuesOnCurrentSynchronizationContextIfDe [MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_ContinuesOnCurrentTaskSchedulerIfDesired(bool flowExecutionContext, bool? continueOnCapturedContext) { using StreamPair streams = await CreateConnectedStreamsAsync().ConfigureAwait(ConfigureAwaitOptions.ForceYielding /* escape xunit sync ctx */); @@ -2221,6 +2279,8 @@ await Task.Factory.StartNew(() => [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ZeroByteRead_BlocksUntilDataAvailableOrNops(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + using StreamPair streams = await CreateConnectedStreamsAsync(); foreach ((Stream writeable, Stream readable) in GetReadWritePairs(streams)) { @@ -2287,9 +2347,10 @@ public virtual async Task ZeroByteRead_BlocksUntilDataAvailableOrNops(ReadWriteM [InlineData(ReadWriteMode.AsyncAPM)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ZeroByteWrite_OtherDataReceivedSuccessfully(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + byte[][] buffers = new[] { Array.Empty(), "hello"u8.ToArray(), Array.Empty(), "world"u8.ToArray() }; using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2338,12 +2399,11 @@ public virtual async Task ZeroByteWrite_OtherDataReceivedSuccessfully(ReadWriteM } } - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_CustomMemoryManager_Success(bool useAsync) { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2410,7 +2470,6 @@ await readable.ReadAsync(readBuffer.Memory.Slice(bytesRead)) : [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ConcurrentBidirectionalReadsWrites_Success() { if (!SupportsConcurrentBidirectionalUse) @@ -2460,24 +2519,23 @@ public static IEnumerable CopyToAsync_AllDataCopied_MemberData() => [OuterLoop("May take several seconds", ~TestPlatforms.Browser)] [SkipOnPlatform(TestPlatforms.Browser, "Not supported on browser")] - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [InlineData(false)] [InlineData(true)] public virtual async Task CopyToAsync_AllDataCopied_Large(bool useAsync) => await CopyToAsync_AllDataCopied(1024 * 1024, useAsync); - [Theory] + [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [MemberData(nameof(CopyToAsync_AllDataCopied_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task CopyToAsync_AllDataCopied(int byteCount, bool useAsync) { using StreamPair streams = await CreateConnectedStreamsAsync(); (Stream writeable, Stream readable) = GetReadWritePair(streams); var results = new MemoryStream(); - byte[] dataToCopy = RandomNumberGenerator.GetBytes(byteCount); + byte[] dataToCopy = GetRandomBytes(byteCount); Task copyTask; if (useAsync) @@ -2501,7 +2559,6 @@ public virtual async Task CopyToAsync_AllDataCopied(int byteCount, bool useAsync [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Parallel_ReadWriteMultipleStreamsConcurrently() { await Task.WhenAll(Enumerable.Range(0, 20).Select(_ => Task.Run(async () => @@ -2513,7 +2570,7 @@ await Task.WhenAll(Enumerable.Range(0, 20).Select(_ => Task.Run(async () => [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/108151", TestPlatforms.Wasi)] public virtual async Task Timeout_Roundtrips() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2550,7 +2607,7 @@ public virtual async Task Timeout_Roundtrips() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/108151", TestPlatforms.Wasi)] public virtual async Task ReadTimeout_Expires_Throws() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2569,7 +2626,6 @@ public virtual async Task ReadTimeout_Expires_Throws() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_CancelPendingRead_DoesntImpactSubsequentReads() { if (!UsableAfterCanceledReads) @@ -2668,7 +2724,6 @@ public virtual async Task ClosedConnection_WritesFailImmediately_ThrowException( [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadAsync_DuringReadAsync_ThrowsIfUnsupported() { if (UnsupportedConcurrentExceptionType is null) @@ -2691,7 +2746,6 @@ public virtual async Task ReadAsync_DuringReadAsync_ThrowsIfUnsupported() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Flush_ValidOnWriteableStreamWithNoData_Success() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2708,7 +2762,6 @@ public virtual async Task Flush_ValidOnWriteableStreamWithNoData_Success() [Fact] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Flush_ValidOnReadableStream_Success() { using StreamPair streams = await CreateConnectedStreamsAsync(); @@ -2728,7 +2781,6 @@ public virtual async Task Flush_ValidOnReadableStream_Success() [InlineData(2)] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task Dispose_ClosesStream(int disposeMode) { if (!CansReturnFalseAfterDispose) @@ -2952,6 +3004,8 @@ await WhenAllOrAnyFailed( [InlineData(ReadWriteMode.AsyncAPM)] public virtual async Task ZeroByteRead_PerformsZeroByteReadOnUnderlyingStreamWhenDataNeeded(ReadWriteMode mode) { + if (SkipOnWasi(mode)) return; + if (!ZeroByteReadPerformsZeroByteReadOnUnderlyingStream) { return; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs index 21f39aa9104987..b9b6d735ffc4f5 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs @@ -403,7 +403,6 @@ public async Task ReadableWriteableProperties_Roundtrip() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task CopyToAsync_DisposedSourceStream_ThrowsOnWindows_NoThrowOnUnix() { await RunWithConnectedNetworkStreamsAsync(async (stream, _) => @@ -441,7 +440,6 @@ await RunWithConnectedNetworkStreamsAsync((stream, _) => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ReadAsync_MultipleConcurrentValueTaskReads_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -462,7 +460,6 @@ await RunWithConnectedNetworkStreamsAsync(async (server, client) => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ReadAsync_MultipleConcurrentValueTaskReads_AsTask_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -483,7 +480,6 @@ await RunWithConnectedNetworkStreamsAsync(async (server, client) => } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task WriteAsync_MultipleConcurrentValueTaskWrites_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -510,7 +506,6 @@ await client.ReadAsync((Memory)b2) + } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task WriteAsync_MultipleConcurrentValueTaskWrites_AsTask_Success() { await RunWithConnectedNetworkStreamsAsync(async (server, client) => @@ -568,8 +563,7 @@ private static async Task RunWithConnectedNetworkStreamsAsync(Func Date: Tue, 24 Sep 2024 17:42:07 +0200 Subject: [PATCH 07/14] more --- .../System.Net.Sockets/tests/FunctionalTests/Accept.cs | 2 +- .../tests/FunctionalTests/LocalEndPointTest.cs | 1 - .../System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs | 1 + .../tests/FunctionalTests/ReceiveMessageFrom.cs | 1 + .../tests/FunctionalTests/SocketAsyncEventArgsTest.cs | 4 +--- 5 files changed, 4 insertions(+), 5 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs index a556bea2295803..d71a8737da4606 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Accept.cs @@ -264,7 +264,6 @@ public async Task Accept_WithInUseTargetSocket_Fails() } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task AcceptAsync_MultipleAcceptsThenDispose_AcceptsThrowAfterDispose() { if (UsesSync) @@ -391,6 +390,7 @@ public sealed class AcceptSyncForceNonBlocking : Accept { public AcceptApm(ITestOutputHelper output) : base(output) {} diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs index 208c78962782b5..b322ebe8cd4a5b 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/LocalEndPointTest.cs @@ -143,7 +143,6 @@ public async Task TcpClientSocket_WhenNotBound_LocalEPChangeToSpecificOnConnect( } [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] // see also https://github.com/WebAssembly/wasi-libc/issues/540 public async Task TcpAcceptSocket_WhenServerBoundToWildcardAddress_LocalEPIsSpecific() { using (Socket server = CreateTcpSocket()) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs index faaefd1fb89fa5..54b11e58ce9a9f 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveFrom.cs @@ -343,6 +343,7 @@ public async Task ClosedBeforeOperation_Throws_ObjectDisposedException(bool clos [InlineData(true)] [InlineData(false)] [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ClosedDuringOperation_Throws_ObjectDisposedExceptionOrSocketException(bool closeOrDispose) { if (UsesSync && PlatformDetection.IsOSX) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs index d126a2dff21f24..654be9e7555ad2 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs @@ -179,6 +179,7 @@ public async Task ClosedBeforeOperation_Throws_ObjectDisposedException(bool clos [InlineData(true)] [InlineData(false)] [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] + //[ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ClosedDuringOperation_Throws_ObjectDisposedExceptionOrSocketException(bool closeOrDispose) { if (UsesSync && PlatformDetection.IsOSX) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs index 2a155776f3d157..9909192150ed0b 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketAsyncEventArgsTest.cs @@ -71,8 +71,7 @@ public void Dispose_MultipleCalls_Success() } } - [Fact] - [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] + [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))] public async Task Dispose_WhileInUse_DisposeDelayed() { using (var listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) @@ -572,7 +571,6 @@ public async Task Connect_WithData_OK(bool useFastOpen, int size) } [Fact] - // [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ReuseSocketAsyncEventArgs_SameInstance_MultipleSockets() { using (var listen = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) From 1a14c50e4fa5100d2be7bae57510e4b8db257c52 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 26 Sep 2024 12:05:27 +0200 Subject: [PATCH 08/14] fix PacketInformation and enable the test --- .../src/System/Net/Sockets/Socket.cs | 16 ++++++- .../IPPacketInformationTest.cs | 36 +++++--------- .../FunctionalTests/ReceiveMessageFrom.cs | 9 ++-- .../libs/System.Native/pal_networking.c | 48 +++++++++++++------ 4 files changed, 62 insertions(+), 47 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 98767eccd96f04..1b32e059304734 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -64,7 +64,7 @@ public partial class Socket : IDisposable private ProtocolType _protocolType; // Bool marked true if the native socket option IP_PKTINFO or IPV6_PKTINFO has been set. - private bool _receivingPacketInformation; + private bool _receivingPacketInformation = OperatingSystem.IsWasi(); private int _closeTimeout = Socket.DefaultCloseTimeout; private bool _disposed; @@ -3166,7 +3166,7 @@ private bool ReceiveMessageFromAsync(SocketAsyncEventArgs e, CancellationToken c // e.m_SocketAddres for Create to work later. e.RemoteEndPoint = endPointSnapshot; - if (!OperatingSystem.IsWasi()) SetReceivingPacketInformation(); + SetReceivingPacketInformation(); // Prepare for and make the native call. e.StartOperationCommon(this, SocketAsyncOperation.ReceiveMessageFrom); @@ -3559,6 +3559,8 @@ internal void SetReceivingPacketInformation() { if (!_receivingPacketInformation) { + if (OperatingSystem.IsWasi()) return; // WASI is always set to receive PacketInformation + // DualMode: When bound to IPv6Any you must enable both socket options. // When bound to an IPv4 mapped IPv6 address you must enable the IPv4 socket option. IPEndPoint? ipEndPoint = _rightEndPoint as IPEndPoint; @@ -3586,6 +3588,16 @@ internal void SetReceivingPacketInformation() internal unsafe void SetSocketOption(SocketOptionLevel optionLevel, SocketOptionName optionName, int optionValue, bool silent) { + // WASI is always set to receive PacketInformation + if (OperatingSystem.IsWasi() && optionName == SocketOptionName.PacketInformation) + { + if (optionValue == 0) + { + UpdateStatusAfterSocketOptionErrorAndThrowException(SocketError.ProtocolOption); + } + return; + } + if (silent && (Disposed || _handle.IsInvalid)) { if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, "skipping the call"); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs index 60304407c4ec58..595a482c016f15 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/IPPacketInformationTest.cs @@ -2,12 +2,12 @@ // The .NET Foundation licenses this file to you under the MIT license. using System.Threading; +using System.Threading.Tasks; using Xunit; namespace System.Net.Sockets.Tests { - [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support IPPacketInformation")] public class IPPacketInformationTest { [Fact] @@ -28,9 +28,9 @@ public void GetHashCode_DefaultValues_Success() } [Fact] - public void Equals_NonDefaultValue_Success() + public async Task Equals_NonDefaultValue_Success() { - IPPacketInformation packetInfo = GetNonDefaultIPPacketInformation(); + IPPacketInformation packetInfo = await GetNonDefaultIPPacketInformation(); IPPacketInformation packetInfoCopy = packetInfo; Assert.Equal(packetInfo, packetInfoCopy); @@ -49,40 +49,28 @@ public void Equals_NonDefaultValue_Success() } [Fact] - public void GetHashCode_NonDefaultValue_Success() + public async Task GetHashCode_NonDefaultValue_Success() { - IPPacketInformation packetInfo = GetNonDefaultIPPacketInformation(); + IPPacketInformation packetInfo = await GetNonDefaultIPPacketInformation(); Assert.Equal(packetInfo.GetHashCode(), packetInfo.GetHashCode()); } - private IPPacketInformation GetNonDefaultIPPacketInformation() + private async Task GetNonDefaultIPPacketInformation() { - const int ReceiveTimeout = 10000; - using (var receiver = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) using (var sender = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)) { int port = receiver.BindToAnonymousPort(IPAddress.Loopback); - - var waitHandle = new ManualResetEvent(false); - - SocketAsyncEventArgs receiveArgs = new SocketAsyncEventArgs { - RemoteEndPoint = new IPEndPoint(IPAddress.Loopback, port), - UserToken = waitHandle - }; - - receiveArgs.SetBuffer(new byte[1], 0, 1); - receiveArgs.Completed += (_, args) => ((ManualResetEvent)args.UserToken).Set(); - - Assert.True(receiver.ReceiveMessageFromAsync(receiveArgs), "receiver.ReceiveMessageFromAsync"); - // Send a few packets, in case they aren't delivered reliably. - sender.SendTo(new byte[1], new IPEndPoint(IPAddress.Loopback, port)); + var receiveTask = receiver.ReceiveMessageFromAsync(new byte[1], new IPEndPoint(IPAddress.Loopback, port)); + var sendTask = sender.SendToAsync(new byte[1], new IPEndPoint(IPAddress.Loopback, port)); + + Assert.True(await Task.WhenAny(receiveTask, Task.Delay(TestSettings.PassingTestTimeout)) == receiveTask, "Timed out"); - Assert.True(waitHandle.WaitOne(ReceiveTimeout), "waitHandle.WaitOne"); + var result = await receiveTask; - return receiveArgs.ReceiveMessageFromPacketInfo; + return result.PacketInformation; } } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs index 654be9e7555ad2..3d957ce09bbfb4 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs @@ -127,7 +127,7 @@ public async Task ReceiveSent_UDP_Success(bool ipv4) using Socket receiver = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); using Socket sender = new Socket(address.AddressFamily, SocketType.Dgram, ProtocolType.Udp); - if (!OperatingSystem.IsWasi()) receiver.SetSocketOption(ipv4 ? SocketOptionLevel.IP : SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true); + receiver.SetSocketOption(ipv4 ? SocketOptionLevel.IP : SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true); ConfigureNonBlocking(sender); ConfigureNonBlocking(receiver); @@ -154,11 +154,8 @@ public async Task ReceiveSent_UDP_Success(bool ipv4) AssertExtensions.SequenceEqual(emptyBuffer, new ReadOnlySpan(receiveInternalBuffer, 0, Offset)); AssertExtensions.SequenceEqual(sendBuffer, new ReadOnlySpan(receiveInternalBuffer, Offset, DatagramSize)); Assert.Equal(sender.LocalEndPoint, result.RemoteEndPoint); - if (!OperatingSystem.IsWasi()) - { - IPPacketInformation packetInformation = result.PacketInformation; - Assert.Equal(((IPEndPoint)sender.LocalEndPoint).Address, packetInformation.Address); - } + IPPacketInformation packetInformation = result.PacketInformation; + Assert.Equal(((IPEndPoint)sender.LocalEndPoint).Address, packetInformation.Address); } } diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c index 83e65a814796a7..ed29e1a1cd02f3 100644 --- a/src/native/libs/System.Native/pal_networking.c +++ b/src/native/libs/System.Native/pal_networking.c @@ -1054,7 +1054,6 @@ static struct cmsghdr* GET_CMSG_NXTHDR(struct msghdr* mhdr, struct cmsghdr* cmsg #pragma clang diagnostic pop #endif } -#endif // CMSG_SPACE int32_t SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isIPv4, IPPacketInformation* packetInfo) @@ -1064,7 +1063,6 @@ SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isI return 0; } -#if defined(CMSG_SPACE) struct msghdr header; ConvertMessageHeaderToMsghdr(&header, messageHeader, -1); @@ -1093,13 +1091,35 @@ SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isI } return 0; -#else // CMSG_SPACE - (void)messageHeader; - (void)isIPv4; - (void)packetInfo; - return Error_ENOTSUP; -#endif // CMSG_SPACE } +#else // !CMSG_SPACE +int32_t +SystemNative_TryGetIPPacketInformation(MessageHeader* messageHeader, int32_t isIPv4, IPPacketInformation* packetInfo) +{ + if (messageHeader == NULL || packetInfo == NULL) + { + return 0; + } + + if (isIPv4 != 0) + { + struct sockaddr_in* inetSockAddr = (struct sockaddr_in*)messageHeader->SocketAddress; + + ConvertInAddrToByteArray(&packetInfo->Address.Address[0], NUM_BYTES_IN_IPV4_ADDRESS, &inetSockAddr->sin_addr); + packetInfo->Address.IsIPv6 = 0; + } + else + { + struct sockaddr_in6* inet6SockAddr = (struct sockaddr_in6*)messageHeader->SocketAddress; + + ConvertIn6AddrToByteArray(&packetInfo->Address.Address[0], NUM_BYTES_IN_IPV6_ADDRESS, &inet6SockAddr->sin6_addr); + packetInfo->Address.IsIPv6 = 1; + packetInfo->Address.ScopeId = inet6SockAddr->sin6_scope_id; + } + packetInfo->InterfaceIndex = 0; + return 1; +} +#endif // !CMSG_SPACE static int8_t GetMulticastOptionName(int32_t multicastOption, int8_t isIPv6, int* optionName) { @@ -1553,18 +1573,16 @@ int32_t SystemNative_ReceiveMessage(intptr_t socket, MessageHeader* messageHeade } ssize_t res; -#if defined(CMSG_SPACE) +#if !defined(CMSG_SPACE) + // we will only use 0th buffer + struct iovec* msg_iov = (struct iovec*)messageHeader->IOVectors; + while ((res = recvfrom(fd, msg_iov[0].iov_base, msg_iov[0].iov_len, socketFlags, (sockaddr *)messageHeader->SocketAddress, (socklen_t*) &(messageHeader->SocketAddressLen))) < 0 && errno == EINTR); +#else // CMSG_SPACE struct msghdr header; ConvertMessageHeaderToMsghdr(&header, messageHeader, fd); while ((res = recvmsg(fd, &header, socketFlags)) < 0 && errno == EINTR); -#else // CMSG_SPACE - // we will only use 0th buffer - struct iovec* msg_iov = (struct iovec*)messageHeader->IOVectors; - while ((res = recvfrom(fd, msg_iov[0].iov_base, msg_iov[0].iov_len, socketFlags, (sockaddr *)messageHeader->SocketAddress, (socklen_t*) &(messageHeader->SocketAddressLen))) < 0 && errno == EINTR); -#endif // CMSG_SPACE -#if defined(CMSG_SPACE) assert(header.msg_name == messageHeader->SocketAddress); // should still be the same location as set in ConvertMessageHeaderToMsghdr assert(header.msg_control == messageHeader->ControlBuffer); From a4fb8660f7a8dc981958db447bd734157f859f8b Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 26 Sep 2024 13:58:50 +0200 Subject: [PATCH 09/14] fix ExclusiveAddressUse --- .../src/System/Net/Sockets/Socket.cs | 1 - .../tests/FunctionalTests/CreateSocketTests.cs | 7 +++++-- .../tests/FunctionalTests/TcpClientTest.cs | 1 - .../tests/FunctionalTests/TcpListenerTest.cs | 5 ++--- src/native/libs/System.Native/pal_networking.c | 15 +++++++++++---- 5 files changed, 18 insertions(+), 11 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 1b32e059304734..110222ed81f3ad 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -501,7 +501,6 @@ public bool ExclusiveAddressUse { throw new InvalidOperationException(SR.net_sockets_mustnotbebound); } - if (OperatingSystem.IsWasi() && value) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ExclusiveAddressUse, value ? 1 : 0); } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs index 8ba08e9cfdbdca..22737d013c22ef 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/CreateSocketTests.cs @@ -385,7 +385,10 @@ public void Ctor_SafeHandle_BasicPropertiesPropagate_Success(AddressFamily addre AssertEqualOrSameException(() => orig.NoDelay, () => copy.NoDelay); if (!OperatingSystem.IsWasi()) Assert.Equal(orig.Available, copy.Available); - if (!OperatingSystem.IsWasi()) Assert.Equal(orig.ExclusiveAddressUse, copy.ExclusiveAddressUse); + if (!OperatingSystem.IsWasi() || protocolType != ProtocolType.Udp) + { + Assert.Equal(orig.ExclusiveAddressUse, copy.ExclusiveAddressUse); + } Assert.Equal(orig.Handle, copy.Handle); Assert.Equal(orig.ReceiveBufferSize, copy.ReceiveBufferSize); if (!OperatingSystem.IsWasi()) Assert.Equal(orig.ReceiveTimeout, copy.ReceiveTimeout); @@ -427,7 +430,7 @@ public async Task Ctor_SafeHandle_Tcp_SendReceive_Success(AddressFamily addressF if (!OperatingSystem.IsWasi()) Assert.True(client.Blocking); AssertEqualOrSameException(() => orig.DontFragment, () => client.DontFragment); AssertEqualOrSameException(() => orig.EnableBroadcast, () => client.EnableBroadcast); - if (!OperatingSystem.IsWasi()) Assert.Equal(orig.ExclusiveAddressUse, client.ExclusiveAddressUse); + Assert.Equal(orig.ExclusiveAddressUse, client.ExclusiveAddressUse); Assert.Equal(orig.Handle, client.Handle); Assert.Equal(orig.IsBound, client.IsBound); if (!OperatingSystem.IsWasi()) Assert.Equal(orig.LingerState.Enabled, client.LingerState.Enabled); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs index a59e888fc33df7..609e215fea88d7 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpClientTest.cs @@ -287,7 +287,6 @@ public void ConnectedAvailable_NullClient() } [Fact] - [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] public void Roundtrip_ExclusiveAddressUse_GetEqualsSet_True() { using (TcpClient client = new TcpClient()) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs index 2611feb416134a..a328b292754157 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/TcpListenerTest.cs @@ -237,7 +237,6 @@ async Task VerifyAccept(TcpListener listener) } [Fact] - [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] public void ExclusiveAddressUse_ListenerNotStarted_SetAndReadSuccessfully() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -249,7 +248,7 @@ public void ExclusiveAddressUse_ListenerNotStarted_SetAndReadSuccessfully() } [Fact] - [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] + [SkipOnPlatform(TestPlatforms.Wasi, "In wasi-libc ExclusiveAddressUse is emulated by fake SO_REUSEADDR")] public void ExclusiveAddressUse_SetStartListenerThenRead_ReadSuccessfully() { var listener = new TcpListener(IPAddress.Loopback, 0); @@ -264,7 +263,7 @@ public void ExclusiveAddressUse_SetStartListenerThenRead_ReadSuccessfully() } [Fact] - [SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support ExclusiveAddressUse")] + [SkipOnPlatform(TestPlatforms.Wasi, "In wasi-libc ExclusiveAddressUse is emulated by fake SO_REUSEADDR")] public void ExclusiveAddressUse_SetStartAndStopListenerThenRead_ReadSuccessfully() { var listener = new TcpListener(IPAddress.Loopback, 0); diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c index ed29e1a1cd02f3..2f79954fcf6beb 100644 --- a/src/native/libs/System.Native/pal_networking.c +++ b/src/native/libs/System.Native/pal_networking.c @@ -2248,7 +2248,11 @@ int32_t SystemNative_GetSockOpt( socklen_t optLen = (socklen_t)*optionLen; // On Unix, SO_REUSEPORT controls the ability to bind multiple sockets to the same address. int err = getsockopt(fd, SOL_SOCKET, SO_REUSEPORT, optionValue, &optLen); - +#elif defined(SO_REUSEADDR) + socklen_t optLen = (socklen_t)*optionLen; + int err = getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, optionValue, &optLen); +#endif +#if defined(SO_REUSEPORT) || defined(SO_REUSEADDR) if (err != 0) { return SystemNative_ConvertErrorPlatformToPal(errno); @@ -2265,7 +2269,7 @@ int32_t SystemNative_GetSockOpt( value = value == 0 ? 1 : 0; } *(int32_t*)optionValue = value; -#else // !SO_REUSEPORT +#else // !SO_REUSEPORT !SO_REUSEADDR *optionValue = 0; #endif return Error_SUCCESS; @@ -2385,7 +2389,6 @@ SystemNative_SetSockOpt(intptr_t socket, int32_t socketOptionLevel, int32_t sock // We make both SocketOptionName_SO_REUSEADDR and SocketOptionName_SO_EXCLUSIVEADDRUSE control SO_REUSEPORT/SO_REUSEADDR. if (socketOptionName == SocketOptionName_SO_EXCLUSIVEADDRUSE || socketOptionName == SocketOptionName_SO_REUSEADDR) { -#ifdef SO_REUSEPORT if (optionLen != sizeof(int32_t)) { return Error_EINVAL; @@ -2406,6 +2409,7 @@ SystemNative_SetSockOpt(intptr_t socket, int32_t socketOptionLevel, int32_t sock } } +#ifdef SO_REUSEPORT // An application that sets SO_REUSEPORT/SO_REUSEADDR can reuse the endpoint with another // application that sets the same option. If one application sets SO_REUSEPORT and another // sets SO_REUSEADDR the second application will fail to bind. We set both options, this @@ -2416,7 +2420,10 @@ SystemNative_SetSockOpt(intptr_t socket, int32_t socketOptionLevel, int32_t sock err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &value, (socklen_t)optionLen); } return err == 0 ? Error_SUCCESS : SystemNative_ConvertErrorPlatformToPal(errno); -#else // !SO_REUSEPORT +#elif defined(SO_REUSEADDR) + int err = setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &value, (socklen_t)optionLen); + return err == 0 ? Error_SUCCESS : SystemNative_ConvertErrorPlatformToPal(errno); +#else // !SO_REUSEPORT !SO_REUSEADDR return Error_SUCCESS; #endif } From 6792226cc01c65cc0431a3fe50a052318f7c4112 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 26 Sep 2024 14:58:52 +0200 Subject: [PATCH 10/14] OSSupportsIPv6DualMode --- .../System.Net.Sockets/src/System/Net/Sockets/Socket.cs | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 110222ed81f3ad..4410a4e28313eb 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -70,9 +70,9 @@ public partial class Socket : IDisposable private bool _disposed; public Socket(SocketType socketType, ProtocolType protocolType) - : this(OSSupportsIPv6 ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, socketType, protocolType) + : this(OSSupportsIPv6DualMode ? AddressFamily.InterNetworkV6 : AddressFamily.InterNetwork, socketType, protocolType) { - if (!OperatingSystem.IsWasi() && OSSupportsIPv6) + if (OSSupportsIPv6DualMode) { DualMode = true; } @@ -259,6 +259,7 @@ private static SafeSocketHandle ValidateHandle(SafeSocketHandle handle) public static bool OSSupportsIPv4 => SocketProtocolSupportPal.OSSupportsIPv4; public static bool OSSupportsIPv6 => SocketProtocolSupportPal.OSSupportsIPv6; + internal static bool OSSupportsIPv6DualMode => !OperatingSystem.IsWasi() && OSSupportsIPv6; public static bool OSSupportsUnixDomainSockets => SocketProtocolSupportPal.OSSupportsUnixDomainSockets; // Gets the amount of data pending in the network's input buffer that can be @@ -745,7 +746,7 @@ public bool DualMode { return false; } - if (OperatingSystem.IsWasi()) + if (!OSSupportsIPv6DualMode) { return false; } @@ -758,7 +759,7 @@ public bool DualMode throw new NotSupportedException(SR.net_invalidversion); } - if (OperatingSystem.IsWasi() && value) throw new PlatformNotSupportedException(); + if (!OSSupportsIPv6DualMode && value) throw new PlatformNotSupportedException(); SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.IPv6Only, value ? 0 : 1); } From fea52aab7099478492ccd658b5192f8ab6ee1c2e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 26 Sep 2024 15:29:58 +0200 Subject: [PATCH 11/14] SuppressFlow --- .../src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs index 3eeffd491835e8..4b65cd22f7c929 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs @@ -132,7 +132,10 @@ public static void HandleSocketEvent(object? state) SocketAsyncContext ctx = (SocketAsyncContext)state!; try { - ctx.HandleEventsInline(Sys.SocketEvents.Write | Sys.SocketEvents.Read); + using (ExecutionContext.SuppressFlow()) + { + ctx.HandleEventsInline(Sys.SocketEvents.Write | Sys.SocketEvents.Read); + } } catch (Exception e) { From 50b197ec351705ed08c2143fc2eefdc57a58d2e6 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Thu, 26 Sep 2024 18:55:37 +0200 Subject: [PATCH 12/14] feedback --- src/mono/sample/wasi/sockets-p2/Program.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/mono/sample/wasi/sockets-p2/Program.cs b/src/mono/sample/wasi/sockets-p2/Program.cs index c26cc8eb52e7e7..44af1d475d61df 100644 --- a/src/mono/sample/wasi/sockets-p2/Program.cs +++ b/src/mono/sample/wasi/sockets-p2/Program.cs @@ -35,9 +35,7 @@ public static async Task MainAsync(string[] args) while (start < messageBytes.Length) { start += await client.SendAsync(messageBytes.AsMemory(start), SocketFlags.None); - Console.WriteLine("TODO poll here"); } - Console.WriteLine("GET sent"); // Receive ack. var buffer = new byte[2048]; From c92b57fb367eb61f8b80dd8c66f195e436223165 Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 2 Oct 2024 10:58:56 +0200 Subject: [PATCH 13/14] feedback --- .../src/System/Net/Sockets/NetworkStream.cs | 18 +-- .../src/System/Net/Sockets/Socket.Unix.cs | 2 +- .../src/System/Net/Sockets/Socket.cs | 141 +++++++++--------- .../Net/Sockets/SocketAsyncContext.Unix.cs | 22 +-- .../Net/Sockets/SocketAsyncEngine.Wasi.cs | 6 +- .../src/System/Net/Sockets/SocketPal.Unix.cs | 1 + .../src/System/Net/Sockets/SocketPal.Wasi.cs | 4 + .../src/System/Net/Sockets/TCPClient.cs | 11 +- .../src/System/Net/Sockets/TCPListener.cs | 2 +- .../src/System/Net/Sockets/UDPClient.cs | 24 +-- .../FunctionalTests/ReceiveMessageFrom.cs | 1 - .../System/Threading/Wasi/WasiEventLoop.cs | 2 +- .../libs/System.Native/pal_networking.c | 3 + 13 files changed, 124 insertions(+), 113 deletions(-) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs index 598dc35aa0e75a..00adb9147ea13f 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs @@ -226,7 +226,7 @@ public override long Seek(long offset, SeekOrigin origin) // Number of bytes we read, or 0 if the socket is closed. public override int Read(byte[] buffer, int offset, int count) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ValidateBufferArguments(buffer, offset, count); ThrowIfDisposed(); @@ -247,7 +247,7 @@ public override int Read(byte[] buffer, int offset, int count) public override int Read(Span buffer) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 if (GetType() != typeof(NetworkStream)) { @@ -272,7 +272,7 @@ public override int Read(Span buffer) public override unsafe int ReadByte() { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 byte b; return Read(new Span(&b, 1)) == 0 ? -1 : b; @@ -296,7 +296,7 @@ public override unsafe int ReadByte() // way to indicate an error. public override void Write(byte[] buffer, int offset, int count) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ValidateBufferArguments(buffer, offset, count); ThrowIfDisposed(); @@ -319,7 +319,7 @@ public override void Write(byte[] buffer, int offset, int count) public override void Write(ReadOnlySpan buffer) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 if (GetType() != typeof(NetworkStream)) { @@ -432,7 +432,7 @@ protected override void Dispose(bool disposing) // An IASyncResult, representing the read. public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ValidateBufferArguments(buffer, offset, count); ThrowIfDisposed(); @@ -467,7 +467,7 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, Asy // The number of bytes read. May throw an exception. public override int EndRead(IAsyncResult asyncResult) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(asyncResult); @@ -498,7 +498,7 @@ public override int EndRead(IAsyncResult asyncResult) // An IASyncResult, representing the write. public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ValidateBufferArguments(buffer, offset, count); ThrowIfDisposed(); @@ -530,7 +530,7 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As // Returns: The number of bytes read. May throw an exception. public override void EndWrite(IAsyncResult asyncResult) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(asyncResult); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs index dc5c872e3d8e76..c90bd301f501cf 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.Unix.cs @@ -63,7 +63,7 @@ private static unsafe void LoadSocketTypeFromHandle( { if (OperatingSystem.IsWasi()) { - // Unify with unix after https://github.com/WebAssembly/wasi-libc/issues/537 + // FIXME: Unify with unix after https://github.com/WebAssembly/wasi-libc/issues/537 blocking = false; Interop.Error e = Interop.Sys.GetSocketType(handle, out addressFamily, out socketType, out protocolType, out isListening); if (e == Interop.Error.ENOTSOCK) diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs index 4410a4e28313eb..1202cacc380900 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs @@ -169,7 +169,7 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) break; case AddressFamily.Unix: - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsUnixDomainSockets) throw new PlatformNotSupportedException(); _rightEndPoint = new UnixDomainSocketEndPoint(buffer.Slice(0, bufferLength)); break; @@ -203,7 +203,7 @@ private unsafe Socket(SafeSocketHandle handle, bool loadPropertiesFromHandle) break; case AddressFamily.Unix: - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsUnixDomainSockets) throw new PlatformNotSupportedException(); _remoteEndPoint = new UnixDomainSocketEndPoint(buffer.Slice(0, bufferLength)); break; @@ -259,7 +259,10 @@ private static SafeSocketHandle ValidateHandle(SafeSocketHandle handle) public static bool OSSupportsIPv4 => SocketProtocolSupportPal.OSSupportsIPv4; public static bool OSSupportsIPv6 => SocketProtocolSupportPal.OSSupportsIPv6; + [UnsupportedOSPlatformGuard("wasi")] internal static bool OSSupportsIPv6DualMode => !OperatingSystem.IsWasi() && OSSupportsIPv6; + [UnsupportedOSPlatformGuard("wasi")] + internal static bool OSSupportsThreads => !OperatingSystem.IsWasi(); public static bool OSSupportsUnixDomainSockets => SocketProtocolSupportPal.OSSupportsUnixDomainSockets; // Gets the amount of data pending in the network's input buffer that can be @@ -581,7 +584,7 @@ public LingerOption? LingerState { get { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (OperatingSystem.IsWasi()) return new LingerOption(false, 0); return (LingerOption?)GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger); } @@ -649,7 +652,7 @@ public bool DontFragment { get { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (OperatingSystem.IsWasi()) return false; if (_addressFamily == AddressFamily.InterNetwork || (_addressFamily == AddressFamily.InterNetworkV6 && DualMode)) { @@ -826,7 +829,7 @@ private void DoBind(EndPoint endPointSnapshot, SocketAddress socketAddress) // Establishes a connection to a remote system. public void Connect(EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(remoteEP); @@ -872,7 +875,7 @@ public void Connect(EndPoint remoteEP) public void Connect(IPAddress address, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(address); @@ -897,7 +900,7 @@ public void Connect(IPAddress address, int port) public void Connect(string host, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(host); @@ -928,7 +931,7 @@ public void Connect(string host, int port) public void Connect(IPAddress[] addresses, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(addresses); @@ -1025,7 +1028,7 @@ public void Listen(int backlog) // Creates a new Sockets.Socket instance to handle an incoming connection. public Socket Accept() { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -1094,35 +1097,35 @@ public Socket Accept() // Sends a data buffer to a connected socket. public int Send(byte[] buffer, int size, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Send(buffer, 0, size, socketFlags); } public int Send(byte[] buffer, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Send(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags); } public int Send(byte[] buffer) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Send(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None); } public int Send(IList> buffers) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Send(buffers, SocketFlags.None); } public int Send(IList> buffers, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SocketError errorCode; int bytesTransferred = Send(buffers, socketFlags, out errorCode); @@ -1135,7 +1138,7 @@ public int Send(IList> buffers, SocketFlags socketFlags) public int Send(IList> buffers, SocketFlags socketFlags, out SocketError errorCode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(buffers); @@ -1173,7 +1176,7 @@ public int Send(IList> buffers, SocketFlags socketFlags, out // Sends data to a connected socket, starting at the indicated location in the buffer. public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SocketError errorCode; int bytesTransferred = Send(buffer, offset, size, socketFlags, out errorCode); @@ -1186,7 +1189,7 @@ public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags) public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -1227,7 +1230,7 @@ public int Send(byte[] buffer, int offset, int size, SocketFlags socketFlags, ou public int Send(ReadOnlySpan buffer, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 int bytesTransferred = Send(buffer, socketFlags, out SocketError errorCode); return errorCode == SocketError.Success ? @@ -1237,7 +1240,7 @@ public int Send(ReadOnlySpan buffer, SocketFlags socketFlags) public int Send(ReadOnlySpan buffer, SocketFlags socketFlags, out SocketError errorCode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBlockingMode(); @@ -1264,7 +1267,7 @@ public int Send(ReadOnlySpan buffer, SocketFlags socketFlags, out SocketEr public void SendFile(string? fileName) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SendFile(fileName, ReadOnlySpan.Empty, ReadOnlySpan.Empty, TransmitFileOptions.UseDefaultWorkerThread); } @@ -1292,7 +1295,7 @@ public void SendFile(string? fileName) /// An error occurred when attempting to access the socket. public void SendFile(string? fileName, byte[]? preBuffer, byte[]? postBuffer, TransmitFileOptions flags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SendFile(fileName, preBuffer.AsSpan(), postBuffer.AsSpan(), flags); } @@ -1320,7 +1323,7 @@ public void SendFile(string? fileName, byte[]? preBuffer, byte[]? postBuffer, Tr /// An error occurred when attempting to access the socket. public void SendFile(string? fileName, ReadOnlySpan preBuffer, ReadOnlySpan postBuffer, TransmitFileOptions flags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -1339,7 +1342,7 @@ public void SendFile(string? fileName, ReadOnlySpan preBuffer, ReadOnlySpa // Sends data to a specific end point, starting at the indicated location in the buffer. public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -1377,21 +1380,21 @@ public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, // Sends data to a specific end point, starting at the indicated location in the data. public int SendTo(byte[] buffer, int size, SocketFlags socketFlags, EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return SendTo(buffer, 0, size, socketFlags, remoteEP); } public int SendTo(byte[] buffer, SocketFlags socketFlags, EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return SendTo(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags, remoteEP); } public int SendTo(byte[] buffer, EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return SendTo(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None, remoteEP); } @@ -1407,7 +1410,7 @@ public int SendTo(byte[] buffer, EndPoint remoteEP) /// The has been closed. public int SendTo(ReadOnlySpan buffer, EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return SendTo(buffer, SocketFlags.None, remoteEP); } @@ -1424,7 +1427,7 @@ public int SendTo(ReadOnlySpan buffer, EndPoint remoteEP) /// The has been closed. public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(remoteEP); @@ -1467,7 +1470,7 @@ public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, EndPoint r /// The has been closed. public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, SocketAddress socketAddress) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(socketAddress); @@ -1496,21 +1499,21 @@ public int SendTo(ReadOnlySpan buffer, SocketFlags socketFlags, SocketAddr // Receives data from a connected socket. public int Receive(byte[] buffer, int size, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Receive(buffer, 0, size, socketFlags); } public int Receive(byte[] buffer, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Receive(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags); } public int Receive(byte[] buffer) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Receive(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None); } @@ -1518,7 +1521,7 @@ public int Receive(byte[] buffer) // Receives data from a connected socket into a specific location of the receive buffer. public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SocketError errorCode; int bytesTransferred = Receive(buffer, offset, size, socketFlags, out errorCode); @@ -1531,7 +1534,7 @@ public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags) public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -1565,7 +1568,7 @@ public int Receive(byte[] buffer, int offset, int size, SocketFlags socketFlags, public int Receive(Span buffer, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 int bytesTransferred = Receive(buffer, socketFlags, out SocketError errorCode); return errorCode == SocketError.Success ? @@ -1575,7 +1578,7 @@ public int Receive(Span buffer, SocketFlags socketFlags) public int Receive(Span buffer, SocketFlags socketFlags, out SocketError errorCode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBlockingMode(); @@ -1602,14 +1605,14 @@ public int Receive(Span buffer, SocketFlags socketFlags, out SocketError e public int Receive(IList> buffers) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return Receive(buffers, SocketFlags.None); } public int Receive(IList> buffers, SocketFlags socketFlags) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SocketError errorCode; int bytesTransferred = Receive(buffers, socketFlags, out errorCode); @@ -1622,7 +1625,7 @@ public int Receive(IList> buffers, SocketFlags socketFlags) public int Receive(IList> buffers, SocketFlags socketFlags, out SocketError errorCode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(buffers); @@ -1661,7 +1664,7 @@ public int Receive(IList> buffers, SocketFlags socketFlags, o // the end point. public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -1740,7 +1743,7 @@ public int ReceiveMessageFrom(byte[] buffer, int offset, int size, ref SocketFla /// You must call the Bind method before performing this operation. public int ReceiveMessageFrom(Span buffer, ref SocketFlags socketFlags, ref EndPoint remoteEP, out IPPacketInformation ipPacketInformation) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(remoteEP); @@ -1802,7 +1805,7 @@ public int ReceiveMessageFrom(Span buffer, ref SocketFlags socketFlags, re // the end point. public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -1883,21 +1886,21 @@ public int ReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFl // Receives a datagram and stores the source end point. public int ReceiveFrom(byte[] buffer, int size, SocketFlags socketFlags, ref EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return ReceiveFrom(buffer, 0, size, socketFlags, ref remoteEP); } public int ReceiveFrom(byte[] buffer, SocketFlags socketFlags, ref EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return ReceiveFrom(buffer, 0, buffer != null ? buffer.Length : 0, socketFlags, ref remoteEP); } public int ReceiveFrom(byte[] buffer, ref EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return ReceiveFrom(buffer, 0, buffer != null ? buffer.Length : 0, SocketFlags.None, ref remoteEP); } @@ -1928,7 +1931,7 @@ public int ReceiveFrom(Span buffer, ref EndPoint remoteEP) /// The has been closed. public int ReceiveFrom(Span buffer, SocketFlags socketFlags, ref EndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateReceiveFromEndpointAndState(remoteEP, nameof(remoteEP)); @@ -2011,7 +2014,7 @@ public int ReceiveFrom(Span buffer, SocketFlags socketFlags, ref EndPoint /// The has been closed. public int ReceiveFrom(Span buffer, SocketFlags socketFlags, SocketAddress receivedAddress) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ArgumentNullException.ThrowIfNull(receivedAddress, nameof(receivedAddress)); @@ -2339,7 +2342,7 @@ public void SetIPProtectionLevel(IPProtectionLevel level) /// The has been closed. public bool Poll(int microSeconds, SelectMode mode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -2386,7 +2389,7 @@ public bool Poll(TimeSpan timeout, SelectMode mode) => /// One or more sockets was disposed. public static void Select(IList? checkRead, IList? checkWrite, IList? checkError, int microSeconds) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 if ((checkRead == null || checkRead.Count == 0) && (checkWrite == null || checkWrite.Count == 0) && @@ -2486,7 +2489,7 @@ public void Disconnect(bool reuseSocket) public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2496,7 +2499,7 @@ public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags s public IAsyncResult? BeginSend(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2514,7 +2517,7 @@ public IAsyncResult BeginSend(byte[] buffer, int offset, int size, SocketFlags s public IAsyncResult BeginSend(IList> buffers, SocketFlags socketFlags, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -2523,7 +2526,7 @@ public IAsyncResult BeginSend(IList> buffers, SocketFlags soc public IAsyncResult? BeginSend(IList> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -2545,14 +2548,14 @@ public int EndSend(IAsyncResult asyncResult, out SocketError errorCode) => public IAsyncResult BeginSendFile(string? fileName, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 return BeginSendFile(fileName, null, null, TransmitFileOptions.UseDefaultWorkerThread, callback, state); } public IAsyncResult BeginSendFile(string? fileName, byte[]? preBuffer, byte[]? postBuffer, TransmitFileOptions flags, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -2570,7 +2573,7 @@ public IAsyncResult BeginSendFile(string? fileName, byte[]? preBuffer, byte[]? p public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags, EndPoint remoteEP, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2584,7 +2587,7 @@ public IAsyncResult BeginSendTo(byte[] buffer, int offset, int size, SocketFlags public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2593,7 +2596,7 @@ public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlag public IAsyncResult? BeginReceive(byte[] buffer, int offset, int size, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2611,7 +2614,7 @@ public IAsyncResult BeginReceive(byte[] buffer, int offset, int size, SocketFlag public IAsyncResult BeginReceive(IList> buffers, SocketFlags socketFlags, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); return TaskToAsyncResult.Begin(ReceiveAsync(buffers, socketFlags), callback, state); @@ -2619,7 +2622,7 @@ public IAsyncResult BeginReceive(IList> buffers, SocketFlags public IAsyncResult? BeginReceive(IList> buffers, SocketFlags socketFlags, out SocketError errorCode, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); Task t = ReceiveAsync(buffers, socketFlags); @@ -2641,7 +2644,7 @@ public int EndReceive(IAsyncResult asyncResult, out SocketError errorCode) => private static int EndSendReceive(IAsyncResult asyncResult, out SocketError errorCode) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 Task ti = TaskToAsyncResult.Unwrap(asyncResult); @@ -2659,7 +2662,7 @@ private static int EndSendReceive(IAsyncResult asyncResult, out SocketError erro public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"size:{size}"); @@ -2682,7 +2685,7 @@ public IAsyncResult BeginReceiveMessageFrom(byte[] buffer, int offset, int size, public int EndReceiveMessageFrom(IAsyncResult asyncResult, ref SocketFlags socketFlags, ref EndPoint endPoint, out IPPacketInformation ipPacketInformation) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ArgumentNullException.ThrowIfNull(endPoint); if (!CanTryAddressFamily(endPoint.AddressFamily)) @@ -2702,7 +2705,7 @@ public int EndReceiveMessageFrom(IAsyncResult asyncResult, ref SocketFlags socke public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, SocketFlags socketFlags, ref EndPoint remoteEP, AsyncCallback? callback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); ValidateBufferArguments(buffer, offset, size); @@ -2722,7 +2725,7 @@ public IAsyncResult BeginReceiveFrom(byte[] buffer, int offset, int size, Socket public int EndReceiveFrom(IAsyncResult asyncResult, ref EndPoint endPoint) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ArgumentNullException.ThrowIfNull(endPoint); if (!CanTryAddressFamily(endPoint.AddressFamily)) @@ -2784,7 +2787,7 @@ public IAsyncResult BeginAccept(Socket? acceptSocket, int receiveSize, AsyncCall public Socket EndAccept(out byte[] buffer, IAsyncResult asyncResult) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 Socket socket = EndAccept(out byte[] innerBuffer, out int bytesTransferred, asyncResult); buffer = new byte[bytesTransferred]; @@ -2794,7 +2797,7 @@ public Socket EndAccept(out byte[] buffer, IAsyncResult asyncResult) public Socket EndAccept(out byte[] buffer, out int bytesTransferred, IAsyncResult asyncResult) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 Socket s; (s, buffer, bytesTransferred) = TaskToAsyncResult.End<(Socket, byte[], int)>(asyncResult); @@ -3666,7 +3669,7 @@ private void SetIPv6MulticastOption(SocketOptionName optionName, IPv6MulticastOp private void SetLingerOption(LingerOption lref) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (OperatingSystem.IsWasi() && lref.Enabled) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 SocketError errorCode = SocketPal.SetLingerOption(_handle, lref); @@ -3681,7 +3684,7 @@ private void SetLingerOption(LingerOption lref) private LingerOption? GetLingerOpt() { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (OperatingSystem.IsWasi()) return new LingerOption(false, 0); LingerOption? lingerOption; SocketError errorCode = SocketPal.GetLingerOption(_handle, out lingerOption); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs index 7bdc2ff0e90492..8463c5142b573c 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncContext.Unix.cs @@ -1367,7 +1367,7 @@ public void SetHandleNonBlocking() private void PerformSyncOperation(ref OperationQueue queue, TOperation operation, int timeout, int observedSequenceNumber) where TOperation : AsyncOperation { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); using (var e = new ManualResetEventSlim(false, 0)) @@ -1504,7 +1504,7 @@ public SocketError AcceptAsync(Memory socketAddress, out int socketAddress public SocketError Connect(Memory socketAddress) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(socketAddress.Length > 0, $"Unexpected socketAddressLen: {socketAddress.Length}"); // Connect is different than the usual "readiness" pattern of other operations. @@ -1598,7 +1598,7 @@ public SocketError ReceiveAsync(Memory buffer, SocketFlags flags, out int public unsafe SocketError ReceiveFrom(Memory buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, int timeout, out int bytesReceived) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); @@ -1631,7 +1631,7 @@ public unsafe SocketError ReceiveFrom(Memory buffer, ref SocketFlags flags public unsafe SocketError ReceiveFrom(Span buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, int timeout, out int bytesReceived) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); SocketFlags receivedFlags; SocketError errorCode; @@ -1743,7 +1743,7 @@ public SocketError ReceiveAsync(IList> buffers, SocketFlags f public unsafe SocketError ReceiveFrom(IList> buffers, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, int timeout, out int bytesReceived) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); @@ -1812,7 +1812,7 @@ public SocketError ReceiveFromAsync(IList> buffers, SocketFla public SocketError ReceiveMessageFrom( Memory buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, bool isIPv4, bool isIPv6, int timeout, out IPPacketInformation ipPacketInformation, out int bytesReceived) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); @@ -1849,7 +1849,7 @@ public SocketError ReceiveMessageFrom( public unsafe SocketError ReceiveMessageFrom( Span buffer, ref SocketFlags flags, Memory socketAddress, out int socketAddressLen, bool isIPv4, bool isIPv6, int timeout, out IPPacketInformation ipPacketInformation, out int bytesReceived) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); @@ -1941,7 +1941,7 @@ public SocketError SendAsync(Memory buffer, int offset, int count, SocketF public SocketError SendTo(byte[] buffer, int offset, int count, SocketFlags flags, Memory socketAddress, int timeout, out int bytesSent) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); @@ -1973,7 +1973,7 @@ public SocketError SendTo(byte[] buffer, int offset, int count, SocketFlags flag public unsafe SocketError SendTo(ReadOnlySpan buffer, SocketFlags flags, Memory socketAddress, int timeout, out int bytesSent) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); @@ -2052,7 +2052,7 @@ public SocketError SendAsync(IList> buffers, SocketFlags flag public SocketError SendTo(IList> buffers, SocketFlags flags, Memory socketAddress, int timeout, out int bytesSent) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); @@ -2122,7 +2122,7 @@ public SocketError SendToAsync(IList> buffers, SocketFlags fl public SocketError SendFile(SafeFileHandle fileHandle, long offset, long count, int timeout, out long bytesSent) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); Debug.Assert(timeout == -1 || timeout > 0, $"Unexpected timeout: {timeout}"); diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs index 4b65cd22f7c929..3b69902260d812 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketAsyncEngine.Wasi.cs @@ -16,8 +16,7 @@ namespace System.Net.Sockets { internal sealed unsafe class SocketAsyncEngine { - internal static readonly bool InlineSocketCompletionsEnabled = Environment.GetEnvironmentVariable("DOTNET_SYSTEM_NET_SOCKETS_INLINE_COMPLETIONS") == "1"; - internal static readonly TaskContinuationOptions ContinuationOptions = InlineSocketCompletionsEnabled ? TaskContinuationOptions.ExecuteSynchronously : TaskContinuationOptions.RunContinuationsAsynchronously; + internal const bool InlineSocketCompletionsEnabled = true; private static readonly SocketAsyncEngine s_engine = new SocketAsyncEngine(); public static bool TryRegisterSocket(IntPtr socketHandle, SocketAsyncContext context, out SocketAsyncEngine? engine, out Interop.Error error) @@ -43,6 +42,9 @@ public void UnregisterSocket(IntPtr _, SocketAsyncContext context) context.unregisterPollHook.Cancel(); } + // this method is invading private implementation details of wasi-libc + // we could get rid of it when https://github.com/WebAssembly/wasi-libc/issues/542 is resolved + // or after WASIp3 promises are implemented, whatever comes first public static IList BeforePollHook(object? state) { var context = (SocketAsyncContext)state!; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs index 8e7882eb2cb52a..eed14c336888e2 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Unix.cs @@ -71,6 +71,7 @@ public static unsafe SocketError CreateSocket(AddressFamily addressFamily, Socke // The socket was created successfully; enable IPV6_V6ONLY by default for normal AF_INET6 sockets. // This fails on raw sockets so we just let them be in default state. + // WASI is always IPv6-only when IPv6 is enabled. if (!OperatingSystem.IsWasi() && addressFamily == AddressFamily.InterNetworkV6 && socketType != SocketType.Raw) { int on = 1; diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs index 439270e2bb6527..3fd6dee783e01c 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Wasi.cs @@ -11,6 +11,10 @@ using System.Threading.Tasks; using Microsoft.Win32.SafeHandles; +// types here are clone of private implementation details of wasi-libc +// we could get rid of it when https://github.com/WebAssembly/wasi-libc/issues/542 is resolved +// or after WASIp3 promises are implemented, whatever comes first + namespace System.Net.Sockets { [StructLayout(LayoutKind.Sequential)] diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs index 0a64e420e47982..41d54eba71d1c2 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPClient.cs @@ -123,7 +123,7 @@ public bool ExclusiveAddressUse // Connects the Client to the specified port on the specified host. public void Connect(string hostname, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -142,7 +142,7 @@ public void Connect(string hostname, int port) // Connects the Client to the specified port on the specified host. public void Connect(IPAddress address, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -159,7 +159,7 @@ public void Connect(IPAddress address, int port) // Connect the Client to the specified end point. public void Connect(IPEndPoint remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -172,7 +172,7 @@ public void Connect(IPEndPoint remoteEP) public void Connect(IPAddress[] ipAddresses, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -239,7 +239,7 @@ public IAsyncResult BeginConnect(IPAddress[] addresses, int port, AsyncCallback? public void EndConnect(IAsyncResult asyncResult) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 _clientSocket.EndConnect(asyncResult); _active = true; @@ -352,7 +352,6 @@ public LingerOption? LingerState { get { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151 return Client.LingerState; } set diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs index 661a4fe95be4f0..647bed93739da8 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/TCPListener.cs @@ -290,7 +290,7 @@ private void CreateNewSocketIfNeeded() private TResult EndAcceptCore(IAsyncResult asyncResult) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 try { diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs index dc05ee34345ad0..60bc380ec195a1 100644 --- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs +++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/UDPClient.cs @@ -284,7 +284,7 @@ public IAsyncResult BeginSend(byte[] datagram, int bytes, string? hostname, int public IAsyncResult BeginSend(byte[] datagram, int bytes, IPEndPoint? endPoint, AsyncCallback? requestCallback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ValidateDatagram(datagram, bytes, endPoint); @@ -301,7 +301,7 @@ public IAsyncResult BeginSend(byte[] datagram, int bytes, IPEndPoint? endPoint, public int EndSend(IAsyncResult asyncResult) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -358,7 +358,7 @@ private void ValidateDatagram(byte[] datagram, int bytes, IPEndPoint? endPoint) public IAsyncResult BeginReceive(AsyncCallback? requestCallback, object? state) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -374,7 +374,7 @@ public IAsyncResult BeginReceive(AsyncCallback? requestCallback, object? state) public byte[] EndReceive(IAsyncResult asyncResult, ref IPEndPoint? remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -685,7 +685,7 @@ public void Close() public void Connect(string hostname, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -800,7 +800,7 @@ public void Connect(string hostname, int port) public void Connect(IPAddress addr, int port) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -817,7 +817,7 @@ public void Connect(IPAddress addr, int port) public void Connect(IPEndPoint endPoint) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -830,7 +830,7 @@ public void Connect(IPEndPoint endPoint) public byte[] Receive([NotNull] ref IPEndPoint? remoteEP) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -853,7 +853,7 @@ public byte[] Receive([NotNull] ref IPEndPoint? remoteEP) // Sends a UDP datagram to the host at the remote end point. public int Send(byte[] dgram, int bytes, IPEndPoint? endPoint) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -889,7 +889,7 @@ public int Send(byte[] dgram, int bytes, IPEndPoint? endPoint) /// An error occurred when accessing the socket. public int Send(ReadOnlySpan datagram, IPEndPoint? endPoint) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -933,7 +933,7 @@ public int Send(ReadOnlySpan datagram, IPEndPoint? endPoint) // Sends a UDP datagram to a remote host. public int Send(byte[] dgram, int bytes) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); @@ -959,7 +959,7 @@ public int Send(byte[] dgram, int bytes) /// An error occurred when accessing the socket. public int Send(ReadOnlySpan datagram) { - if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 + if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185 ThrowIfDisposed(); diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs index 3d957ce09bbfb4..d6161b3e9d0958 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ReceiveMessageFrom.cs @@ -176,7 +176,6 @@ public async Task ClosedBeforeOperation_Throws_ObjectDisposedException(bool clos [InlineData(true)] [InlineData(false)] [ActiveIssue("https://github.com/dotnet/runtime/issues/52124", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)] - //[ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task ClosedDuringOperation_Throws_ObjectDisposedExceptionOrSocketException(bool closeOrDispose) { if (UsesSync && PlatformDetection.IsOSX) diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs index 371b40ac8b3d84..d89fa4f34e65e9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Wasi/WasiEventLoop.cs @@ -281,7 +281,7 @@ public static void Dispose(object? s) return; } - // it will be removed from s_pollables on the next run + // it will be removed from s_hooks on the next run self.isDisposed = true; self.cancellationTokenRegistration.Dispose(); } diff --git a/src/native/libs/System.Native/pal_networking.c b/src/native/libs/System.Native/pal_networking.c index 2f79954fcf6beb..3efd4f7ae4f963 100644 --- a/src/native/libs/System.Native/pal_networking.c +++ b/src/native/libs/System.Native/pal_networking.c @@ -3373,6 +3373,9 @@ static int32_t WaitForSocketEventsInner(int32_t port, SocketEvent* buffer, int32 // from https://github.com/WebAssembly/wasi-libc/blob/230d4be6c54bec93181050f9e25c87150506bdd0/libc-bottom-half/headers/private/wasi/descriptor_table.h bool descriptor_table_get_ref(int fd, void **entry); +// this method is invading private implementation details of wasi-libc +// we could get rid of it when https://github.com/WebAssembly/wasi-libc/issues/542 is resolved +// or after WASIp3 promises are implemented, whatever comes first int32_t SystemNative_GetWasiSocketDescriptor(intptr_t socket, void** entry) { if (entry == NULL) From 4a28c7e2107ba322000475354c6345e44daff42e Mon Sep 17 00:00:00 2001 From: pavelsavara Date: Wed, 2 Oct 2024 11:15:24 +0200 Subject: [PATCH 14/14] testing issues --- .../StreamConformanceTests/System/IO/StreamConformanceTests.cs | 2 ++ .../tests/FunctionalTests/NetworkStreamTest.cs | 2 ++ 2 files changed, 4 insertions(+) diff --git a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs index 441b88811d5baf..61fb0f51936e27 100644 --- a/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs +++ b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs @@ -1807,6 +1807,7 @@ from writeSize in new[] { 10 * 1024 * 1024 } [SkipOnPlatform(TestPlatforms.Browser, "Not supported on browser")] [Theory] [MemberData(nameof(ReadWrite_Success_Large_MemberData))] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_Success_Large(ReadWriteMode mode, int writeSize, bool startWithFlush) => await ReadWrite_Success(mode, writeSize, startWithFlush); @@ -1814,6 +1815,7 @@ public virtual async Task ReadWrite_Success_Large(ReadWriteMode mode, int writeS [MemberData(nameof(ReadWrite_Success_MemberData))] [SkipOnPlatform(TestPlatforms.LinuxBionic, "SElinux blocks UNIX sockets in our CI environment")] [SkipOnPlatform(TestPlatforms.iOS | TestPlatforms.tvOS, "iOS/tvOS blocks binding to UNIX sockets")] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public virtual async Task ReadWrite_Success(ReadWriteMode mode, int writeSize, bool startWithFlush) { if (SkipOnWasi(mode)) return; diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs index b9b6d735ffc4f5..f4e51b061a86fc 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/NetworkStreamTest.cs @@ -163,6 +163,7 @@ public async Task Ctor_SocketFileAccessBool_CanReadAndWrite_DoesntOwn(FileAccess [Theory] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task Ctor_SocketBool_CanReadAndWrite(bool ownsSocket) { using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) @@ -296,6 +297,7 @@ await RunWithConnectedNetworkStreamsAsync(async (server, client) => [Theory] [InlineData(false)] [InlineData(true)] + [ActiveIssue("https://github.com/dotnet/runtime/issues/107981", TestPlatforms.Wasi)] public async Task DisposedClosed_MembersThrowObjectDisposedException(bool close) { await RunWithConnectedNetworkStreamsAsync((server, _) =>