diff --git a/eng/testing/tests.wasi.targets b/eng/testing/tests.wasi.targets
index 3fb2112131b170..7f981dde513c7f 100644
--- a/eng/testing/tests.wasi.targets
+++ b/eng/testing/tests.wasi.targets
@@ -49,6 +49,8 @@
<_XHarnessArgs Condition="'$(WasmXHarnessTestsTimeout)' != ''" >$(_XHarnessArgs) "--timeout=$(WasmXHarnessTestsTimeout)"
<_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/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/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/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs b/src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs
index c36ce7c6feb0a0..61fb0f51936e27 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