Skip to content

Commit 81efcad

Browse files
authored
[WASI] sockets (#106977)
1 parent 7474054 commit 81efcad

File tree

74 files changed

+1624
-240
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

74 files changed

+1624
-240
lines changed

eng/testing/tests.wasi.targets

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,8 @@
4949
<_XHarnessArgs Condition="'$(WasmXHarnessTestsTimeout)' != ''" >$(_XHarnessArgs) &quot;--timeout=$(WasmXHarnessTestsTimeout)&quot;</_XHarnessArgs>
5050
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=http</_XHarnessArgs>
5151
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=inherit-network</_XHarnessArgs>
52+
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=tcp</_XHarnessArgs>
53+
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=udp</_XHarnessArgs>
5254
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=allow-ip-name-lookup</_XHarnessArgs>
5355
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--env --engine-arg=DOTNET_WASI_PRINT_EXIT_CODE=1</_XHarnessArgs>
5456
<_XHarnessArgs Condition="'$(WasmXHarnessArgsCli)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgsCli)</_XHarnessArgs>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System;
5+
using System.Runtime.InteropServices;
6+
7+
internal static partial class Interop
8+
{
9+
internal static partial class Sys
10+
{
11+
[Flags]
12+
internal enum SocketEvents : int
13+
{
14+
None = 0x00,
15+
Read = 0x01,
16+
Write = 0x02,
17+
ReadClose = 0x04,
18+
Close = 0x08,
19+
Error = 0x10
20+
}
21+
22+
[LibraryImport(Libraries.SystemNative, EntryPoint = "SystemNative_GetWasiSocketDescriptor")]
23+
internal static unsafe partial Error GetWasiSocketDescriptor(IntPtr socket, IntPtr* entry);
24+
}
25+
}

src/libraries/Common/src/System/Net/SocketProtocolSupportPal.Unix.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ private static unsafe bool IsSupported(AddressFamily af)
1414
{
1515
// Check for AF_UNIX on iOS/tvOS. The OS claims to support this, but returns EPERM on bind.
1616
// We should explicitly set the return here to false, to avoid giving a false impression.
17-
if (af == AddressFamily.Unix && (OperatingSystem.IsTvOS() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst())))
17+
if (af == AddressFamily.Unix && (OperatingSystem.IsTvOS() || OperatingSystem.IsWasi() || (OperatingSystem.IsIOS() && !OperatingSystem.IsMacCatalyst())))
1818
{
1919
return false;
2020
}

src/libraries/Common/src/System/Threading/Tasks/TaskToAsyncResult.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ static class TaskToAsyncResult
3232
public static IAsyncResult Begin(Task task, AsyncCallback? callback, object? state)
3333
{
3434
#if NET
35+
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
36+
3537
ArgumentNullException.ThrowIfNull(task);
3638
#else
3739
if (task is null)

src/libraries/Common/tests/StreamConformanceTests/System/IO/StreamConformanceTests.cs

Lines changed: 106 additions & 22 deletions
Large diffs are not rendered by default.

src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.UnixDomainSockets.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
namespace System.IO.Pipes.Tests
99
{
10+
[SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support UnixDomain")]
1011
public class NamedPipeTest_UnixDomainSockets
1112
{
1213
[Fact]

src/libraries/System.Net.Sockets/Directory.Build.props

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@
33
<PropertyGroup>
44
<StrongNameKeyId>Microsoft</StrongNameKeyId>
55
<IncludePlatformAttributes>true</IncludePlatformAttributes>
6-
<!-- WASI until https://github.com/dotnet/runtime/issues/98957 -->
7-
<UnsupportedOSPlatforms>browser;wasi</UnsupportedOSPlatforms>
6+
<UnsupportedOSPlatforms>browser</UnsupportedOSPlatforms>
87
</PropertyGroup>
98
</Project>

src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<Project Sdk="Microsoft.NET.Sdk">
22

33
<PropertyGroup>
4-
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)</TargetFrameworks>
4+
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)</TargetFrameworks>
55
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
66
<!-- SYSTEM_NET_SOCKETS_DLL is required to allow source-level code sharing for types defined within the
77
System.Net.Internals namespace. -->
@@ -48,7 +48,7 @@
4848
<Compile Include="System\Net\Sockets\TransmitFileOptions.cs" />
4949
<Compile Include="System\Net\Sockets\UDPClient.cs" />
5050
<Compile Include="System\Net\Sockets\UdpReceiveResult.cs" />
51-
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.cs" />
51+
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.cs" Condition="'$(TargetPlatformIdentifier)' != 'wasi'"/>
5252
<!-- Common sources -->
5353
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs"
5454
Link="Common\DisableRuntimeMarshalling.cs" />
@@ -183,14 +183,28 @@
183183
Link="Common\System\Net\CompletionPortHelper.Windows.cs" />
184184
</ItemGroup>
185185

186+
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'wasi'">
187+
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.Wasi.cs" />
188+
<Compile Include="System\Net\Sockets\SocketAsyncContext.Wasi.cs" />
189+
<Compile Include="System\Net\Sockets\SocketAsyncEngine.Wasi.cs"/>
190+
<Compile Include="System\Net\Sockets\SocketPal.Wasi.cs" />
191+
<Compile Include="$(CommonPath)Interop\Wasi\System.Native\Interop.SocketEvent.cs"
192+
Link="Common\Interop\Wasi\System.Native\Interop.SocketEvent.cs" />
193+
</ItemGroup>
194+
186195
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'unix' or '$(TargetPlatformIdentifier)' == 'osx' or '$(TargetPlatformIdentifier)' == 'ios' or '$(TargetPlatformIdentifier)' == 'tvos'">
196+
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.Unix.cs"/>
197+
<Compile Include="System\Net\Sockets\SocketAsyncEngine.Unix.cs" />
198+
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.SocketEvent.cs"
199+
Link="Common\Interop\Unix\System.Native\Interop.SocketEvent.cs" />
200+
</ItemGroup>
201+
202+
<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'unix' or '$(TargetPlatformIdentifier)' == 'wasi' or '$(TargetPlatformIdentifier)' == 'osx' or '$(TargetPlatformIdentifier)' == 'ios' or '$(TargetPlatformIdentifier)' == 'tvos'">
187203
<Compile Include="System\Net\Sockets\SafeSocketHandle.Unix.cs" />
188204
<Compile Include="System\Net\Sockets\Socket.Unix.cs" />
189205
<Compile Include="System\Net\Sockets\SocketAsyncContext.Unix.cs" />
190-
<Compile Include="System\Net\Sockets\SocketAsyncEngine.Unix.cs" />
191206
<Compile Include="System\Net\Sockets\SocketAsyncEventArgs.Unix.cs" />
192207
<Compile Include="System\Net\Sockets\SocketPal.Unix.cs" />
193-
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.Unix.cs" />
194208
<Compile Include="$(CommonPath)System\Net\InteropIPAddressExtensions.Unix.cs"
195209
Link="Common\System\Net\InteropIPAddressExtensions.Unix.cs" />
196210
<Compile Include="$(CommonPath)System\Net\SocketAddressPal.Unix.cs"
@@ -277,8 +291,6 @@
277291
Link="Common\Interop\Unix\System.Native\Interop.Shutdown.cs" />
278292
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Socket.cs"
279293
Link="Common\Interop\Unix\System.Native\Interop.Socket.cs" />
280-
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.SocketEvent.cs"
281-
Link="Common\Interop\Unix\System.Native\Interop.SocketEvent.cs" />
282294
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.SocketAddress.cs"
283295
Link="Common\Interop\Unix\System.Native\Interop.SocketAddress.cs" />
284296
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Pipe.cs"

src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ public NetworkStream(Socket socket, FileAccess access, bool ownsSocket)
4646
{
4747
ArgumentNullException.ThrowIfNull(socket);
4848

49-
if (!socket.Blocking)
49+
if (!OperatingSystem.IsWasi() && !socket.Blocking)
5050
{
5151
// Stream.Read*/Write* are incompatible with the semantics of non-blocking sockets, and
5252
// allowing non-blocking sockets could result in non-deterministic failures from those
@@ -118,6 +118,8 @@ public override int ReadTimeout
118118
{
119119
get
120120
{
121+
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151
122+
121123
int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)!;
122124
if (timeout == 0)
123125
{
@@ -127,6 +129,8 @@ public override int ReadTimeout
127129
}
128130
set
129131
{
132+
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151
133+
130134
if (value <= 0 && value != System.Threading.Timeout.Infinite)
131135
{
132136
throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero);
@@ -141,6 +145,8 @@ public override int WriteTimeout
141145
{
142146
get
143147
{
148+
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151
149+
144150
int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)!;
145151
if (timeout == 0)
146152
{
@@ -150,6 +156,8 @@ public override int WriteTimeout
150156
}
151157
set
152158
{
159+
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151
160+
153161
if (value <= 0 && value != System.Threading.Timeout.Infinite)
154162
{
155163
throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero);
@@ -218,6 +226,8 @@ public override long Seek(long offset, SeekOrigin origin)
218226
// Number of bytes we read, or 0 if the socket is closed.
219227
public override int Read(byte[] buffer, int offset, int count)
220228
{
229+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
230+
221231
ValidateBufferArguments(buffer, offset, count);
222232
ThrowIfDisposed();
223233
if (!CanRead)
@@ -237,6 +247,8 @@ public override int Read(byte[] buffer, int offset, int count)
237247

238248
public override int Read(Span<byte> buffer)
239249
{
250+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
251+
240252
if (GetType() != typeof(NetworkStream))
241253
{
242254
// 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<byte> buffer)
260272

261273
public override unsafe int ReadByte()
262274
{
275+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
276+
263277
byte b;
264278
return Read(new Span<byte>(&b, 1)) == 0 ? -1 : b;
265279
}
@@ -282,6 +296,8 @@ public override unsafe int ReadByte()
282296
// way to indicate an error.
283297
public override void Write(byte[] buffer, int offset, int count)
284298
{
299+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
300+
285301
ValidateBufferArguments(buffer, offset, count);
286302
ThrowIfDisposed();
287303
if (!CanWrite)
@@ -303,6 +319,8 @@ public override void Write(byte[] buffer, int offset, int count)
303319

304320
public override void Write(ReadOnlySpan<byte> buffer)
305321
{
322+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
323+
306324
if (GetType() != typeof(NetworkStream))
307325
{
308326
// 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)
414432
// An IASyncResult, representing the read.
415433
public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
416434
{
435+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
436+
417437
ValidateBufferArguments(buffer, offset, count);
418438
ThrowIfDisposed();
419439
if (!CanRead)
@@ -447,6 +467,8 @@ public override IAsyncResult BeginRead(byte[] buffer, int offset, int count, Asy
447467
// The number of bytes read. May throw an exception.
448468
public override int EndRead(IAsyncResult asyncResult)
449469
{
470+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
471+
450472
ThrowIfDisposed();
451473
ArgumentNullException.ThrowIfNull(asyncResult);
452474

@@ -476,6 +498,8 @@ public override int EndRead(IAsyncResult asyncResult)
476498
// An IASyncResult, representing the write.
477499
public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, AsyncCallback? callback, object? state)
478500
{
501+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
502+
479503
ValidateBufferArguments(buffer, offset, count);
480504
ThrowIfDisposed();
481505
if (!CanWrite)
@@ -506,6 +530,8 @@ public override IAsyncResult BeginWrite(byte[] buffer, int offset, int count, As
506530
// Returns: The number of bytes read. May throw an exception.
507531
public override void EndWrite(IAsyncResult asyncResult)
508532
{
533+
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185
534+
509535
ThrowIfDisposed();
510536
ArgumentNullException.ThrowIfNull(asyncResult);
511537

@@ -659,6 +685,8 @@ public override void SetLength(long value)
659685
private int _currentWriteTimeout = -1;
660686
internal void SetSocketTimeoutOption(SocketShutdown mode, int timeout, bool silent)
661687
{
688+
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151
689+
662690
if (timeout < 0)
663691
{
664692
timeout = 0; // -1 becomes 0 for the winsock stack

src/libraries/System.Net.Sockets/src/System/Net/Sockets/SafeSocketHandle.Unix.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,11 @@ private unsafe SocketError DoCloseHandle(bool abortive)
231231
{
232232
return SocketPal.GetSocketErrorForErrorCode(CloseHandle(handle));
233233
}
234+
if (OperatingSystem.IsWasi())
235+
{
236+
// WASI never blocks and doesn't support linger options
237+
return SocketPal.GetSocketErrorForErrorCode(CloseHandle(handle));
238+
}
234239

235240
// If abortive is not set, we're not running on the finalizer thread, so it's safe to block here.
236241
// We can honor the linger options set on the socket. It also means closesocket() might return

0 commit comments

Comments
 (0)