Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WASI] sockets #106977

Merged
merged 16 commits into from
Oct 2, 2024
2 changes: 2 additions & 0 deletions eng/testing/tests.wasi.targets
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,8 @@
<_XHarnessArgs Condition="'$(WasmXHarnessTestsTimeout)' != ''" >$(_XHarnessArgs) &quot;--timeout=$(WasmXHarnessTestsTimeout)&quot;</_XHarnessArgs>
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=http</_XHarnessArgs>
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=inherit-network</_XHarnessArgs>
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=tcp</_XHarnessArgs>
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=udp</_XHarnessArgs>
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--wasi --engine-arg=allow-ip-name-lookup</_XHarnessArgs>
<_XHarnessArgs >$(_XHarnessArgs) --engine-arg=--env --engine-arg=DOTNET_WASI_PRINT_EXIT_CODE=1</_XHarnessArgs>
<_XHarnessArgs Condition="'$(WasmXHarnessArgsCli)' != ''" >$(_XHarnessArgs) $(WasmXHarnessArgsCli)</_XHarnessArgs>
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace System.IO.Pipes.Tests
{
[SkipOnPlatform(TestPlatforms.Wasi, "Wasi doesn't support UnixDomain")]
public class NamedPipeTest_UnixDomainSockets
{
[Fact]
Expand Down
3 changes: 1 addition & 2 deletions src/libraries/System.Net.Sockets/Directory.Build.props
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<PropertyGroup>
<StrongNameKeyId>Microsoft</StrongNameKeyId>
<IncludePlatformAttributes>true</IncludePlatformAttributes>
<!-- WASI until https://github.com/dotnet/runtime/issues/98957 -->
<UnsupportedOSPlatforms>browser;wasi</UnsupportedOSPlatforms>
<UnsupportedOSPlatforms>browser</UnsupportedOSPlatforms>
</PropertyGroup>
</Project>
24 changes: 18 additions & 6 deletions src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)</TargetFrameworks>
<TargetFrameworks>$(NetCoreAppCurrent)-windows;$(NetCoreAppCurrent)-unix;$(NetCoreAppCurrent)-osx;$(NetCoreAppCurrent)-ios;$(NetCoreAppCurrent)-tvos;$(NetCoreAppCurrent)-wasi;$(NetCoreAppCurrent)</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- SYSTEM_NET_SOCKETS_DLL is required to allow source-level code sharing for types defined within the
System.Net.Internals namespace. -->
Expand Down Expand Up @@ -48,7 +48,7 @@
<Compile Include="System\Net\Sockets\TransmitFileOptions.cs" />
<Compile Include="System\Net\Sockets\UDPClient.cs" />
<Compile Include="System\Net\Sockets\UdpReceiveResult.cs" />
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.cs" />
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.cs" Condition="'$(TargetPlatformIdentifier)' != 'wasi'"/>
<!-- Common sources -->
<Compile Include="$(CommonPath)DisableRuntimeMarshalling.cs"
Link="Common\DisableRuntimeMarshalling.cs" />
Expand Down Expand Up @@ -183,14 +183,28 @@
Link="Common\System\Net\CompletionPortHelper.Windows.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'wasi'">
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.Wasi.cs" />
<Compile Include="System\Net\Sockets\SocketAsyncContext.Wasi.cs" />
<Compile Include="System\Net\Sockets\SocketAsyncEngine.Wasi.cs"/>
<Compile Include="System\Net\Sockets\SocketPal.Wasi.cs" />
<Compile Include="$(CommonPath)Interop\Wasi\System.Native\Interop.SocketEvent.cs"
Link="Common\Interop\Wasi\System.Native\Interop.SocketEvent.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'unix' or '$(TargetPlatformIdentifier)' == 'osx' or '$(TargetPlatformIdentifier)' == 'ios' or '$(TargetPlatformIdentifier)' == 'tvos'">
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.Unix.cs"/>
<Compile Include="System\Net\Sockets\SocketAsyncEngine.Unix.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.SocketEvent.cs"
Link="Common\Interop\Unix\System.Native\Interop.SocketEvent.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetPlatformIdentifier)' == 'unix' or '$(TargetPlatformIdentifier)' == 'wasi' or '$(TargetPlatformIdentifier)' == 'osx' or '$(TargetPlatformIdentifier)' == 'ios' or '$(TargetPlatformIdentifier)' == 'tvos'">
<Compile Include="System\Net\Sockets\SafeSocketHandle.Unix.cs" />
<Compile Include="System\Net\Sockets\Socket.Unix.cs" />
<Compile Include="System\Net\Sockets\SocketAsyncContext.Unix.cs" />
<Compile Include="System\Net\Sockets\SocketAsyncEngine.Unix.cs" />
<Compile Include="System\Net\Sockets\SocketAsyncEventArgs.Unix.cs" />
<Compile Include="System\Net\Sockets\SocketPal.Unix.cs" />
<Compile Include="System\Net\Sockets\UnixDomainSocketEndPoint.Unix.cs" />
<Compile Include="$(CommonPath)System\Net\InteropIPAddressExtensions.Unix.cs"
Link="Common\System\Net\InteropIPAddressExtensions.Unix.cs" />
<Compile Include="$(CommonPath)System\Net\SocketAddressPal.Unix.cs"
Expand Down Expand Up @@ -277,8 +291,6 @@
Link="Common\Interop\Unix\System.Native\Interop.Shutdown.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Socket.cs"
Link="Common\Interop\Unix\System.Native\Interop.Socket.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.SocketEvent.cs"
Link="Common\Interop\Unix\System.Native\Interop.SocketEvent.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.SocketAddress.cs"
Link="Common\Interop\Unix\System.Native\Interop.SocketAddress.cs" />
<Compile Include="$(CommonPath)Interop\Unix\System.Native\Interop.Pipe.cs"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public NetworkStream(Socket socket, FileAccess access, bool ownsSocket)
{
ArgumentNullException.ThrowIfNull(socket);

if (!socket.Blocking)
if (!OperatingSystem.IsWasi() && !socket.Blocking)
{
// Stream.Read*/Write* are incompatible with the semantics of non-blocking sockets, and
// allowing non-blocking sockets could result in non-deterministic failures from those
Expand Down Expand Up @@ -118,6 +118,8 @@ public override int ReadTimeout
{
get
{
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151

int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout)!;
if (timeout == 0)
{
Expand All @@ -127,6 +129,8 @@ public override int ReadTimeout
}
set
{
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151

if (value <= 0 && value != System.Threading.Timeout.Infinite)
{
throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero);
Expand All @@ -141,6 +145,8 @@ public override int WriteTimeout
{
get
{
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151

int timeout = (int)_streamSocket.GetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout)!;
if (timeout == 0)
{
Expand All @@ -150,6 +156,8 @@ public override int WriteTimeout
}
set
{
if (OperatingSystem.IsWasi()) throw new PlatformNotSupportedException(); // https://github.com/dotnet/runtime/issues/108151

if (value <= 0 && value != System.Threading.Timeout.Infinite)
{
throw new ArgumentOutOfRangeException(nameof(value), SR.net_io_timeout_use_gt_zero);
Expand Down Expand Up @@ -218,6 +226,8 @@ 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

ValidateBufferArguments(buffer, offset, count);
ThrowIfDisposed();
if (!CanRead)
Expand All @@ -237,6 +247,8 @@ public override int Read(byte[] buffer, int offset, int count)

public override int Read(Span<byte> 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
Expand All @@ -260,6 +272,8 @@ public override int Read(Span<byte> 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<byte>(&b, 1)) == 0 ? -1 : b;
}
Expand All @@ -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)
Expand All @@ -303,6 +319,8 @@ public override void Write(byte[] buffer, int offset, int count)

public override void Write(ReadOnlySpan<byte> 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
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
Loading
Loading