Imported Upstream version 5.16.0.100

Former-commit-id: 38faa55fb9669e35e7d8448b15c25dc447f25767
This commit is contained in:
Xamarin Public Jenkins (auto-signing)
2018-08-07 15:19:03 +00:00
parent 0a9828183b
commit 7d7f676260
4419 changed files with 170950 additions and 90273 deletions

View File

@@ -276,6 +276,30 @@ namespace System.Net.Sockets.Tests
Assert.Throws<InvalidOperationException>(() => { AcceptAsync(listener, server); });
}
}
[Fact]
public async Task AcceptAsync_MultipleAcceptsThenDispose_AcceptsThrowAfterDispose()
{
if (UsesSync)
{
return;
}
for (int i = 0; i < 100; i++)
{
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
listener.Listen(2);
Task accept1 = AcceptAsync(listener);
Task accept2 = AcceptAsync(listener);
listener.Dispose();
await Assert.ThrowsAnyAsync<Exception>(() => accept1);
await Assert.ThrowsAnyAsync<Exception>(() => accept2);
}
}
}
}
public sealed class AcceptSync : Accept<SocketHelperArraySync> { }

View File

@@ -44,9 +44,7 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[ActiveIssue(22765, TestPlatforms.AnyUnix)]
public async Task Connect_OnConnectedSocket_Fails()
{
int port;

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,89 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.Net.Sockets.Tests
{
public partial class ExecutionContextFlowTest : FileCleanupTestBase
{
[Fact]
public Task ExecutionContext_FlowsOnlyOnceAcrossAsyncOperations()
{
return Task.Run(async () => // escape xunit's sync ctx
{
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
listener.Listen(1);
client.Connect(listener.LocalEndPoint);
using (Socket server = listener.Accept())
{
var stackLog = new StringBuilder();
int executionContextChanges = 0;
var asyncLocal = new AsyncLocal<int>(_ =>
{
executionContextChanges++;
stackLog.AppendLine($"#{executionContextChanges}: {Environment.StackTrace}");
});
Assert.Equal(0, executionContextChanges);
int numAwaits = 20;
for (int i = 1; i <= numAwaits; i++)
{
asyncLocal.Value = i;
await new AwaitWithOnCompletedInvocation<int>(
client.ReceiveAsync(new Memory<byte>(new byte[1]), SocketFlags.None),
() => server.Send(new byte[1]));
Assert.Equal(i, asyncLocal.Value);
}
// This doesn't count EC changes where EC.Run is passed the same context
// as is current, but it's the best we can track via public API.
try
{
Assert.InRange(executionContextChanges, 1, numAwaits * 3); // at most: 1 / AsyncLocal change + 1 / suspend + 1 / resume
}
catch (Exception e)
{
throw new Exception($"{nameof(executionContextChanges)} == {executionContextChanges} with log: {stackLog.ToString()}", e);
}
}
}
});
}
private readonly struct AwaitWithOnCompletedInvocation<T> : ICriticalNotifyCompletion
{
private readonly ValueTask<T> _valueTask;
private readonly Action _invokeAfterOnCompleted;
public AwaitWithOnCompletedInvocation(ValueTask<T> valueTask, Action invokeAfterOnCompleted)
{
_valueTask = valueTask;
_invokeAfterOnCompleted = invokeAfterOnCompleted;
}
public AwaitWithOnCompletedInvocation<T> GetAwaiter() => this;
public bool IsCompleted => false;
public T GetResult() => _valueTask.GetAwaiter().GetResult();
public void OnCompleted(Action continuation) => throw new NotSupportedException();
public void UnsafeOnCompleted(Action continuation)
{
_valueTask.GetAwaiter().UnsafeOnCompleted(continuation);
_invokeAfterOnCompleted();
}
}
}
}

View File

@@ -454,6 +454,21 @@ namespace System.Net.Sockets.Tests
}
}
[Fact]
public async Task ReadWrite_Byte_Success()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
for (byte i = 0; i < 10; i++)
{
Task<int> read = Task.Run(() => client.ReadByte());
Task write = Task.Run(() => server.WriteByte(i));
await Task.WhenAll(read, write);
Assert.Equal(i, await read);
}
});
}
[Fact]
public async Task ReadWrite_Array_Success()
{

View File

@@ -2,6 +2,9 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -43,17 +46,333 @@ namespace System.Net.Sockets.Tests
});
}
[Fact]
public async Task ReadWrite_Memory_LargeWrite_Success()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
var writeBuffer = new byte[10 * 1024 * 1024];
var readBuffer = new byte[writeBuffer.Length];
RandomNumberGenerator.Fill(writeBuffer);
ValueTask writeTask = client.WriteAsync((ReadOnlyMemory<byte>)writeBuffer);
int totalRead = 0;
while (totalRead < readBuffer.Length)
{
int bytesRead = await server.ReadAsync(new Memory<byte>(readBuffer).Slice(totalRead));
Assert.InRange(bytesRead, 0, int.MaxValue);
if (bytesRead == 0)
{
break;
}
totalRead += bytesRead;
}
Assert.Equal(readBuffer.Length, totalRead);
Assert.Equal<byte>(writeBuffer, readBuffer);
await writeTask;
});
}
[Fact]
public async Task ReadWrite_Precanceled_Throws()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.WriteAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)));
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.ReadAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)).AsTask());
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.WriteAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)));
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReadAsync((ArraySegment<byte>)new byte[0], new CancellationToken(true)));
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.WriteAsync((ReadOnlyMemory<byte>)new byte[0], new CancellationToken(true)));
await Assert.ThrowsAnyAsync<OperationCanceledException>(() => server.ReadAsync((Memory<byte>)new byte[0], new CancellationToken(true)).AsTask());
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.WriteAsync((ReadOnlyMemory<byte>)new byte[0], new CancellationToken(true)));
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReadAsync((Memory<byte>)new byte[0], new CancellationToken(true)));
});
}
[Fact]
public async Task ReadAsync_AwaitMultipleTimes_Throws()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
var b = new byte[1];
ValueTask<int> r = server.ReadAsync(b);
await client.WriteAsync(new byte[] { 42 });
Assert.Equal(1, await r);
Assert.Equal(42, b[0]);
await Assert.ThrowsAsync<InvalidOperationException>(async () => await r);
Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().IsCompleted);
Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().OnCompleted(() => { }));
Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().GetResult());
});
}
[Fact]
public async Task ReadAsync_MultipleContinuations_Throws()
{
await RunWithConnectedNetworkStreamsAsync((server, client) =>
{
var b = new byte[1];
ValueTask<int> r = server.ReadAsync(b);
r.GetAwaiter().OnCompleted(() => { });
Assert.Throws<InvalidOperationException>(() => r.GetAwaiter().OnCompleted(() => { }));
return Task.CompletedTask;
});
}
[Fact]
public async Task ReadAsync_MultipleConcurrentValueTaskReads_Success()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
// Technically this isn't supported behavior, but it happens to work because it's supported on socket.
// So validate it to alert us to any potential future breaks.
byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
ValueTask<int> r1 = server.ReadAsync(b1);
ValueTask<int> r2 = server.ReadAsync(b2);
ValueTask<int> r3 = server.ReadAsync(b3);
await client.WriteAsync(new byte[] { 42, 43, 44 });
Assert.Equal(3, await r1 + await r2 + await r3);
Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
});
}
[Fact]
public async Task ReadAsync_MultipleConcurrentValueTaskReads_AsTask_Success()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
// Technically this isn't supported behavior, but it happens to work because it's supported on socket.
// So validate it to alert us to any potential future breaks.
byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
Task<int> r1 = server.ReadAsync((Memory<byte>)b1).AsTask();
Task<int> r2 = server.ReadAsync((Memory<byte>)b2).AsTask();
Task<int> r3 = server.ReadAsync((Memory<byte>)b3).AsTask();
await client.WriteAsync(new byte[] { 42, 43, 44 });
Assert.Equal(3, await r1 + await r2 + await r3);
Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
});
}
[Fact]
public async Task WriteAsync_MultipleConcurrentValueTaskWrites_Success()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
// Technically this isn't supported behavior, but it happens to work because it's supported on socket.
// So validate it to alert us to any potential future breaks.
ValueTask s1 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 42 }));
ValueTask s2 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 43 }));
ValueTask s3 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 44 }));
byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
Assert.Equal(3,
await client.ReadAsync((Memory<byte>)b1) +
await client.ReadAsync((Memory<byte>)b2) +
await client.ReadAsync((Memory<byte>)b3));
await s1;
await s2;
await s3;
Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
});
}
[Fact]
public async Task WriteAsync_MultipleConcurrentValueTaskWrites_AsTask_Success()
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
// Technically this isn't supported behavior, but it happens to work because it's supported on socket.
// So validate it to alert us to any potential future breaks.
Task s1 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 42 })).AsTask();
Task s2 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 43 })).AsTask();
Task s3 = server.WriteAsync(new ReadOnlyMemory<byte>(new byte[] { 44 })).AsTask();
byte[] b1 = new byte[1], b2 = new byte[1], b3 = new byte[1];
Task<int> r1 = client.ReadAsync((Memory<byte>)b1).AsTask();
Task<int> r2 = client.ReadAsync((Memory<byte>)b2).AsTask();
Task<int> r3 = client.ReadAsync((Memory<byte>)b3).AsTask();
await Task.WhenAll(s1, s2, s3, r1, r2, r3);
Assert.Equal(3, await r1 + await r2 + await r3);
Assert.Equal(42 + 43 + 44, b1[0] + b2[0] + b3[0]);
});
}
public static IEnumerable<object[]> ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData() =>
from flowExecutionContext in new[] { true, false }
from continueOnCapturedContext in new bool?[] { null, false, true }
select new object[] { flowExecutionContext, continueOnCapturedContext };
[Theory]
[MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))]
public async Task ReadAsync_ContinuesOnCurrentSynchronizationContextIfDesired(
bool flowExecutionContext, bool? continueOnCapturedContext)
{
await Task.Run(async () => // escape xunit sync ctx
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
Assert.Null(SynchronizationContext.Current);
var continuationRan = new TaskCompletionSource<bool>();
var asyncLocal = new AsyncLocal<int>();
bool schedulerWasFlowed = false;
bool executionContextWasFlowed = false;
Action continuation = () =>
{
schedulerWasFlowed = SynchronizationContext.Current is CustomSynchronizationContext;
executionContextWasFlowed = 42 == asyncLocal.Value;
continuationRan.SetResult(true);
};
var readBuffer = new byte[1];
ValueTask<int> readValueTask = client.ReadAsync((Memory<byte>)new byte[1]);
SynchronizationContext.SetSynchronizationContext(new CustomSynchronizationContext());
asyncLocal.Value = 42;
switch (continueOnCapturedContext)
{
case null:
if (flowExecutionContext)
{
readValueTask.GetAwaiter().OnCompleted(continuation);
}
else
{
readValueTask.GetAwaiter().UnsafeOnCompleted(continuation);
}
break;
default:
if (flowExecutionContext)
{
readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(continuation);
}
else
{
readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(continuation);
}
break;
}
asyncLocal.Value = 0;
SynchronizationContext.SetSynchronizationContext(null);
Assert.False(readValueTask.IsCompleted);
Assert.False(readValueTask.IsCompletedSuccessfully);
await server.WriteAsync(new byte[] { 42 });
await continuationRan.Task;
Assert.True(readValueTask.IsCompleted);
Assert.True(readValueTask.IsCompletedSuccessfully);
Assert.Equal(continueOnCapturedContext != false, schedulerWasFlowed);
Assert.Equal(flowExecutionContext, executionContextWasFlowed);
});
});
}
[Theory]
[MemberData(nameof(ReadAsync_ContinuesOnCurrentContextIfDesired_MemberData))]
public async Task ReadAsync_ContinuesOnCurrentTaskSchedulerIfDesired(
bool flowExecutionContext, bool? continueOnCapturedContext)
{
await Task.Run(async () => // escape xunit sync ctx
{
await RunWithConnectedNetworkStreamsAsync(async (server, client) =>
{
Assert.Null(SynchronizationContext.Current);
var continuationRan = new TaskCompletionSource<bool>();
var asyncLocal = new AsyncLocal<int>();
bool schedulerWasFlowed = false;
bool executionContextWasFlowed = false;
Action continuation = () =>
{
schedulerWasFlowed = TaskScheduler.Current is CustomTaskScheduler;
executionContextWasFlowed = 42 == asyncLocal.Value;
continuationRan.SetResult(true);
};
var readBuffer = new byte[1];
ValueTask<int> readValueTask = client.ReadAsync((Memory<byte>)new byte[1]);
await Task.Factory.StartNew(() =>
{
Assert.IsType<CustomTaskScheduler>(TaskScheduler.Current);
asyncLocal.Value = 42;
switch (continueOnCapturedContext)
{
case null:
if (flowExecutionContext)
{
readValueTask.GetAwaiter().OnCompleted(continuation);
}
else
{
readValueTask.GetAwaiter().UnsafeOnCompleted(continuation);
}
break;
default:
if (flowExecutionContext)
{
readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().OnCompleted(continuation);
}
else
{
readValueTask.ConfigureAwait(continueOnCapturedContext.Value).GetAwaiter().UnsafeOnCompleted(continuation);
}
break;
}
asyncLocal.Value = 0;
}, CancellationToken.None, TaskCreationOptions.None, new CustomTaskScheduler());
Assert.False(readValueTask.IsCompleted);
Assert.False(readValueTask.IsCompletedSuccessfully);
await server.WriteAsync(new byte[] { 42 });
await continuationRan.Task;
Assert.True(readValueTask.IsCompleted);
Assert.True(readValueTask.IsCompletedSuccessfully);
Assert.Equal(continueOnCapturedContext != false, schedulerWasFlowed);
Assert.Equal(flowExecutionContext, executionContextWasFlowed);
});
});
}
private sealed class CustomSynchronizationContext : SynchronizationContext
{
public override void Post(SendOrPostCallback d, object state)
{
ThreadPool.QueueUserWorkItem(delegate
{
SetSynchronizationContext(this);
try
{
d(state);
}
finally
{
SetSynchronizationContext(null);
}
}, null);
}
}
private sealed class CustomTaskScheduler : TaskScheduler
{
protected override void QueueTask(Task task) => ThreadPool.QueueUserWorkItem(_ => TryExecuteTask(task));
protected override bool TryExecuteTaskInline(Task task, bool taskWasPreviouslyQueued) => false;
protected override IEnumerable<Task> GetScheduledTasks() => null;
}
}
}

View File

@@ -81,9 +81,9 @@ namespace System.Net.Sockets.Tests
}
}
[ActiveIssue(25639)]
[PlatformSpecific(TestPlatforms.AnyUnix)]
[Fact]
public void IOControl_SIOCATMARK_Success()
public void IOControl_SIOCATMARK_Unix_Success()
{
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
@@ -101,25 +101,89 @@ namespace System.Net.Sockets.Tests
{
byte[] siocatmarkResult = new byte[sizeof(int)];
// Socket connected but no data sent.
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
Assert.Equal(0, BitConverter.ToInt32(siocatmarkResult, 0));
server.Send(new byte[] { 42 }, SocketFlags.None);
server.Send(new byte[] { 43 }, SocketFlags.OutOfBand);
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
Assert.Equal(0, BitConverter.ToInt32(siocatmarkResult, 0));
// OOB data recieved, but read pointer not at mark.
Assert.True(SpinWait.SpinUntil(() =>
{
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
return BitConverter.ToInt32(siocatmarkResult, 0) == 0;
}, 10_000));
var received = new byte[1];
Assert.Equal(1, client.Receive(received));
Assert.Equal(42, received[0]);
// OOB data recieved, read pointer at mark.
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
Assert.Equal(1, BitConverter.ToInt32(siocatmarkResult, 0));
Assert.Equal(1, client.Receive(received, SocketFlags.OutOfBand));
Assert.Equal(43, received[0]);
// OOB data read, read pointer at mark.
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
Assert.Equal(PlatformDetection.IsOSX ? 0 : 1, BitConverter.ToInt32(siocatmarkResult, 0));
}
}
}
}
[PlatformSpecific(TestPlatforms.Windows)]
[Fact]
public void IOControl_SIOCATMARK_Windows_Success()
{
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
Assert.Throws<SocketException>(() => client.IOControl(IOControlCode.OobDataRead, null, null));
Assert.Throws<SocketException>(() => client.IOControl(IOControlCode.OobDataRead, null, new byte[0]));
Assert.Throws<SocketException>(() => client.IOControl(IOControlCode.OobDataRead, null, new byte[sizeof(int) - 1]));
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
listener.Listen(1);
client.Connect(listener.LocalEndPoint);
using (Socket server = listener.Accept())
{
byte[] siocatmarkResult = new byte[sizeof(int)];
// Socket connected but no data sent.
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
Assert.Equal(1, BitConverter.ToInt32(siocatmarkResult, 0));
server.Send(new byte[] { 42 }, SocketFlags.None);
server.Send(new byte[] { 43 }, SocketFlags.OutOfBand);
// OOB data recieved, but read pointer not at mark
Assert.True(SpinWait.SpinUntil(() =>
{
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
return BitConverter.ToInt32(siocatmarkResult, 0) == 1;
return BitConverter.ToInt32(siocatmarkResult, 0) == 0;
}, 10_000));
var received = new byte[1];
Assert.Equal(1, client.Receive(received));
Assert.Equal(42, received[0]);
// OOB data recieved, read pointer at mark.
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
Assert.Equal(0, BitConverter.ToInt32(siocatmarkResult, 0));
Assert.Equal(1, client.Receive(received, SocketFlags.OutOfBand));
Assert.Equal(43, received[0]);
// OOB data read, read pointer at mark.
Assert.Equal(4, client.IOControl(IOControlCode.OobDataRead, null, siocatmarkResult));
Assert.Equal(1, BitConverter.ToInt32(siocatmarkResult, 0));
}
}
}

View File

@@ -286,11 +286,12 @@ namespace System.Net.Sockets.Tests
AssertExtensions.Throws<ArgumentException>("path", null, () =>
{
// Existence is validated on send
SendPackets(type, new SendPacketsElement(" \t "), 0);
SendPackets(type, new SendPacketsElement(" "), 0);
});
}
[Theory]
[ActiveIssue(27269)]
[InlineData(SocketImplementationType.APM)]
[InlineData(SocketImplementationType.Async)]
[PlatformSpecific(TestPlatforms.Windows)] // valid filename chars on Unix

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using Xunit;
@@ -1196,7 +1197,74 @@ namespace System.Net.Sockets.Tests
}
}
public sealed class SendReceiveSync : SendReceive<SocketHelperArraySync> { }
public sealed class SendReceiveSync : SendReceive<SocketHelperArraySync>
{
[OuterLoop]
[Fact]
public void BlockingRead_DoesntRequireAnotherThreadPoolThread()
{
RemoteInvoke(() =>
{
// Set the max number of worker threads to a low value.
ThreadPool.GetMaxThreads(out int workerThreads, out int completionPortThreads);
ThreadPool.SetMaxThreads(Environment.ProcessorCount, completionPortThreads);
// Create twice that many socket pairs, for good measure.
(Socket, Socket)[] socketPairs = Enumerable.Range(0, Environment.ProcessorCount * 2).Select(_ => CreateConnectedSocketPair()).ToArray();
try
{
// Ensure that on Unix all of the first socket in each pair are configured for sync-over-async.
foreach ((Socket, Socket) pair in socketPairs)
{
pair.Item1.ForceNonBlocking(force: true);
}
// Queue a work item for each first socket to do a blocking receive.
Task[] receives =
(from pair in socketPairs
select Task.Factory.StartNew(() => pair.Item1.Receive(new byte[1]), CancellationToken.None, TaskCreationOptions.PreferFairness, TaskScheduler.Default))
.ToArray();
// Give a bit of time for the pool to start executing the receives. It's possible this won't be enough,
// in which case the test we could get a false negative on the test, but we won't get spurious failures.
Thread.Sleep(1000);
// Now send to each socket.
foreach ((Socket, Socket) pair in socketPairs)
{
pair.Item2.Send(new byte[1]);
}
// And wait for all the receives to complete.
Assert.True(Task.WaitAll(receives, 60_000), "Expected all receives to complete within timeout");
}
finally
{
foreach ((Socket, Socket) pair in socketPairs)
{
pair.Item1.Dispose();
pair.Item2.Dispose();
}
}
}).Dispose();
}
private static (Socket, Socket) CreateConnectedSocketPair()
{
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
listener.Listen(1);
Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
client.Connect(listener.LocalEndPoint);
Socket server = listener.Accept();
return (client, server);
}
}
}
public sealed class SendReceiveSyncForceNonBlocking : SendReceive<SocketHelperSyncForceNonBlocking> { }
public sealed class SendReceiveApm : SendReceive<SocketHelperApm> { }
public sealed class SendReceiveTask : SendReceive<SocketHelperTask> { }

View File

@@ -2,10 +2,58 @@
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Threading;
using System.Threading.Tasks;
using Xunit;
namespace System.Net.Sockets.Tests
{
public sealed class SendReceiveSpanSync : SendReceive<SocketHelperSpanSync> { }
public sealed class SendReceiveSpanSyncForceNonBlocking : SendReceive<SocketHelperSpanSyncForceNonBlocking> { }
public sealed class SendReceiveMemoryArrayTask : SendReceive<SocketHelperMemoryArrayTask> { }
public sealed class SendReceiveMemoryArrayTask : SendReceive<SocketHelperMemoryArrayTask>
{
[Fact]
public async Task Precanceled_Throws()
{
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.BindToAnonymousPort(IPAddress.Loopback);
listener.Listen(1);
await client.ConnectAsync(listener.LocalEndPoint);
using (Socket server = await listener.AcceptAsync())
{
var cts = new CancellationTokenSource();
cts.Cancel();
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.SendAsync((ReadOnlyMemory<byte>)new byte[0], SocketFlags.None, cts.Token));
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReceiveAsync((Memory<byte>)new byte[0], SocketFlags.None, cts.Token));
}
}
}
[Fact]
public async Task DisposedSocket_ThrowsOperationCanceledException()
{
using (var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
using (var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.BindToAnonymousPort(IPAddress.Loopback);
listener.Listen(1);
await client.ConnectAsync(listener.LocalEndPoint);
using (Socket server = await listener.AcceptAsync())
{
var cts = new CancellationTokenSource();
cts.Cancel();
server.Shutdown(SocketShutdown.Both);
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.SendAsync((ReadOnlyMemory<byte>)new byte[0], SocketFlags.None, cts.Token));
await Assert.ThrowsAnyAsync<OperationCanceledException>(async () => await server.ReceiveAsync((Memory<byte>)new byte[0], SocketFlags.None, cts.Token));
}
}
}
}
public sealed class SendReceiveMemoryNativeTask : SendReceive<SocketHelperMemoryNativeTask> { }
}

View File

@@ -4,6 +4,10 @@
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using Xunit;
namespace System.Net.Sockets.Tests
@@ -48,7 +52,7 @@ namespace System.Net.Sockets.Tests
byte[] array = new byte[42];
saea.SetBuffer(array, 0, array.Length);
Assert.True(saea.MemoryBuffer.TryGetArray(out ArraySegment<byte> result));
Assert.True(MemoryMarshal.TryGetArray(saea.MemoryBuffer, out ArraySegment<byte> result));
Assert.Same(array, result.Array);
Assert.Same(saea.Buffer, array);
Assert.Equal(0, result.Offset);
@@ -59,7 +63,7 @@ namespace System.Net.Sockets.Tests
Assert.Equal(1, saea.Offset);
Assert.Equal(2, saea.Count);
Assert.True(saea.MemoryBuffer.TryGetArray(out result));
Assert.True(MemoryMarshal.TryGetArray(saea.MemoryBuffer, out result));
Assert.Same(array, result.Array);
Assert.Equal(0, result.Offset);
Assert.Equal(array.Length, result.Count);
@@ -181,15 +185,64 @@ namespace System.Net.Sockets.Tests
[Fact]
public void SetBufferMemory_NonArray_BufferReturnsNull()
{
using (var m = new NativeOwnedMemory(42))
using (var m = new NativeMemoryManager(42))
using (var saea = new SocketAsyncEventArgs())
{
saea.SetBuffer(m.Memory);
Assert.True(saea.MemoryBuffer.Equals(m.Memory));
Assert.Equal(0, saea.Offset);
Assert.Equal(m.Length, saea.Count);
Assert.Equal(m.Memory.Length, saea.Count);
Assert.Null(saea.Buffer);
}
}
[OuterLoop("Involves GC and finalization")]
[Theory]
[InlineData(false)]
[InlineData(true)]
public void Finalizer_InvokedWhenNoLongerReferenced(bool afterAsyncOperation)
{
var cwt = new ConditionalWeakTable<object, object>();
for (int i = 0; i < 5; i++) // create several SAEA instances, stored into cwt
{
CreateSocketAsyncEventArgs();
void CreateSocketAsyncEventArgs() // separated out so that JIT doesn't extend lifetime of SAEA instances
{
var saea = new SocketAsyncEventArgs();
cwt.Add(saea, saea);
if (afterAsyncOperation)
{
using (Socket listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
listener.Bind(new IPEndPoint(IPAddress.Loopback, 0));
listener.Listen(1);
using (Socket client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
saea.RemoteEndPoint = listener.LocalEndPoint;
using (var mres = new ManualResetEventSlim())
{
saea.Completed += (s, e) => mres.Set();
if (client.ConnectAsync(saea))
{
mres.Wait();
}
}
}
}
}
}
}
Assert.True(SpinWait.SpinUntil(() =>
{
GC.Collect();
GC.WaitForPendingFinalizers();
return cwt.Count() == 0; // validate that the cwt becomes empty
}, 30_000));
}
}
}

View File

@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
@@ -269,7 +270,7 @@ namespace System.Net.Sockets.Tests
// MemberDatas that are generally useful
//
public abstract class MemberDatas
public abstract class MemberDatas : RemoteExecutorTestBase
{
public static readonly object[][] Loopbacks = new[]
{

View File

@@ -39,7 +39,7 @@ namespace System.Net.Sockets.Tests
public override bool ValidatesArrayArguments => false;
public override async Task<int> ReceiveAsync(Socket s, ArraySegment<byte> buffer)
{
using (var m = new NativeOwnedMemory(buffer.Count))
using (var m = new NativeMemoryManager(buffer.Count))
{
int bytesReceived = await s.ReceiveAsync(m.Memory, SocketFlags.None).ConfigureAwait(false);
m.Memory.Span.Slice(0, bytesReceived).CopyTo(buffer.AsSpan());
@@ -48,7 +48,7 @@ namespace System.Net.Sockets.Tests
}
public override async Task<int> SendAsync(Socket s, ArraySegment<byte> buffer)
{
using (var m = new NativeOwnedMemory(buffer.Count))
using (var m = new NativeMemoryManager(buffer.Count))
{
buffer.AsSpan().CopyTo(m.Memory.Span);
return await s.SendAsync(m.Memory, SocketFlags.None).ConfigureAwait(false);

View File

@@ -21,6 +21,8 @@
<Compile Include="DisposedSocketTests.cs" />
<Compile Include="DnsEndPointTest.cs" />
<Compile Include="DualModeSocketTest.cs" />
<Compile Include="ExecutionContextFlowTest.cs" />
<Compile Include="ExecutionContextFlowTest.netcoreapp.cs" Condition="'$(TargetGroup)' != 'netstandard'" />
<Compile Include="IPPacketInformationTest.cs" />
<Compile Include="LingerStateTest.cs" />
<Compile Include="LoggingTest.cs" />
@@ -48,7 +50,6 @@
<Compile Include="SocketOptionNameTest.cs" />
<Compile Include="MulticastOptionTest.cs" />
<Compile Include="UdpClientTest.cs" />
<Compile Include="UnixDomainSocketTest.cs" />
<Compile Include="UnixDomainSocketTest.netcoreapp.cs" Condition="'$(TargetGroup)' != 'netstandard'" />
<!-- Common Sockets files -->
<Compile Include="$(CommonTestPath)\System\Net\Configuration.cs">
@@ -97,8 +98,8 @@
<Compile Include="$(CommonTestPath)\System\Threading\Tasks\TaskTimeoutExtensions.cs">
<Link>Common\System\Threading\Tasks\TaskTimeoutExtensions.cs</Link>
</Compile>
<Compile Include="$(CommonTestPath)\System\Buffers\NativeOwnedMemory.cs">
<Link>Common\System\Buffers\NativeOwnedMemory.cs</Link>
<Compile Include="$(CommonTestPath)\System\Buffers\NativeMemoryManager.cs">
<Link>Common\System\Buffers\NativeMemoryManager.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\System\Threading\Tasks\TaskToApm.cs">
<Link>Common\System\Threading\Tasks\TaskToApm.cs</Link>
@@ -119,5 +120,8 @@
<ItemGroup>
<EmbeddedResource Include="Resources\$(AssemblyName).rd.xml" />
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>

View File

@@ -124,6 +124,24 @@ namespace System.Net.Sockets.Tests
listener.Stop();
}
[Fact]
// This verify that basic constructs do work when IPv6 is NOT available.
public void IPv6_Only_Works()
{
if (Socket.OSSupportsIPv6 || !Socket.OSSupportsIPv4)
{
// TBD we should figure out better way how to execute this in IPv4 only environment.
return;
}
// This should not throw e.g. default to IPv6.
TcpListener l = TcpListener.Create(0);
l.Stop();
Socket s = new Socket(SocketType.Stream, ProtocolType.Tcp);
s.Close();
}
private sealed class DerivedTcpListener : TcpListener
{
#pragma warning disable 0618

View File

@@ -1,30 +0,0 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
using System.Net.Test.Common;
using Xunit;
using Xunit.Abstractions;
namespace System.Net.Sockets.Tests
{
public partial class UnixDomainSocketTest
{
private readonly ITestOutputHelper _log;
public UnixDomainSocketTest(ITestOutputHelper output)
{
_log = TestLogging.GetInstance();
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[PlatformSpecific(TestPlatforms.Windows)] // CreateUnixDomainSocket should throw on Windows
public void Socket_CreateUnixDomainSocket_Throws_OnWindows()
{
SocketException e = Assert.Throws<SocketException>(() => new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified));
Assert.Equal(SocketError.AddressFamilyNotSupported, e.SocketErrorCode);
}
}
}

View File

@@ -15,16 +15,8 @@ namespace System.Net.Sockets.Tests
{
public partial class UnixDomainSocketTest
{
[Fact]
[PlatformSpecific(TestPlatforms.Windows)] // new UnixDomainSocketEndPoint should throw on Windows
public void UnixDomainSocketEndPoint_Throws_OnWindows()
{
Assert.Throws<PlatformNotSupportedException>(() => new UnixDomainSocketEndPoint("/path"));
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConnectAsyncUnixDomainSocketEndPoint success on Unix
[PlatformSpecific(~TestPlatforms.Windows)] // Windows doesn't currently support ConnectEx with domain sockets
[ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task Socket_ConnectAsyncUnixDomainSocketEndPoint_Success()
{
string path = null;
@@ -79,9 +71,7 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConnectAsyncUnixDomainSocketEndPoint seccess on Unix
[ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task Socket_ConnectAsyncUnixDomainSocketEndPoint_NotServer()
{
string path = GetRandomNonExistingFilePath();
@@ -103,7 +93,9 @@ namespace System.Net.Sockets.Tests
await complete.Task;
}
Assert.Equal(SocketError.AddressNotAvailable, args.SocketError);
Assert.Equal(
RuntimeInformation.IsOSPlatform(OSPlatform.Windows) ? SocketError.InvalidArgument : SocketError.AddressNotAvailable,
args.SocketError);
}
}
finally
@@ -113,9 +105,7 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests SendReceive success for UnixDomainSocketEndPoint on Unix
[ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public void Socket_SendReceive_Success()
{
string path = GetRandomNonExistingFilePath();
@@ -152,9 +142,7 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests SendReceiveAsync success for UnixDomainSocketEndPoint on Unix
[ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task Socket_SendReceiveAsync_Success()
{
string path = GetRandomNonExistingFilePath();
@@ -191,13 +179,11 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Theory]
[ConditionalTheory(nameof(PlatformSupportsUnixDomainSockets))]
[InlineData(5000, 1, 1)]
[InlineData(500, 18, 21)]
[InlineData(500, 21, 18)]
[InlineData(5, 128000, 64000)]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests SendReceiveAsync success for UnixDomainSocketEndPoint on Unix
public async Task Socket_SendReceiveAsync_PropagateToStream_Success(int iterations, int writeBufferSize, int readBufferSize)
{
var writeBuffer = new byte[writeBufferSize * iterations];
@@ -219,10 +205,15 @@ namespace System.Net.Sockets.Tests
Task clientReceives = Task.Run(async () =>
{
int bytesRead;
byte[] buffer = new byte[readBufferSize];
while ((bytesRead = await client.ReceiveAsync(new ArraySegment<byte>(buffer), SocketFlags.None)) > 0)
while (true)
{
int bytesRead = await client.ReceiveAsync(new Memory<byte>(buffer), SocketFlags.None);
if (bytesRead == 0)
{
break;
}
Assert.InRange(bytesRead, 1, writeBuffer.Length - readData.Length);
readData.Write(buffer, 0, bytesRead);
}
});
@@ -250,11 +241,9 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Theory]
[ConditionalTheory(nameof(PlatformSupportsUnixDomainSockets))]
[InlineData(false)]
[InlineData(true)]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConcurrentSendReceive success for UnixDomainSocketEndPoint on Unix
public async Task ConcurrentSendReceive(bool forceNonBlocking)
{
using (Socket server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
@@ -296,9 +285,7 @@ namespace System.Net.Sockets.Tests
}
}
[OuterLoop] // TODO: Issue #11345
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests ConcurrentSendReceive success for UnixDomainSocketEndPoint on Unix
[ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public async Task ConcurrentSendReceiveAsync()
{
using (Socket server = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified))
@@ -336,8 +323,7 @@ namespace System.Net.Sockets.Tests
}
}
[Fact]
[PlatformSpecific(TestPlatforms.AnyUnix)] // Tests new UnixDomainSocketEndPoint throws the correct exception for invalid args
[ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
public void UnixDomainSocketEndPoint_InvalidPaths_Throws()
{
Assert.Throws<ArgumentNullException>(() => new UnixDomainSocketEndPoint(null));
@@ -351,8 +337,7 @@ namespace System.Net.Sockets.Tests
Assert.Throws<ArgumentOutOfRangeException>(() => new UnixDomainSocketEndPoint(invalidLengthString));
}
[Theory]
[PlatformSpecific(TestPlatforms.AnyUnix)]
[ConditionalTheory(nameof(PlatformSupportsUnixDomainSockets))]
[InlineData(false)]
[InlineData(true)]
public void UnixDomainSocketEndPoint_RemoteEndPointEqualsBindAddress(bool abstractAddress)
@@ -412,7 +397,7 @@ namespace System.Net.Sockets.Tests
}
}
[Fact]
[ConditionalFact(nameof(PlatformSupportsUnixDomainSockets))]
[PlatformSpecific(TestPlatforms.AnyUnix & ~TestPlatforms.Linux)] // Don't support abstract socket addresses.
public void UnixDomainSocketEndPoint_UsingAbstractSocketAddressOnUnsupported_Throws()
{
@@ -432,6 +417,16 @@ namespace System.Net.Sockets.Tests
}
}
[ConditionalFact(nameof(PlatformDoesntSupportUnixDomainSockets))]
[PlatformSpecific(TestPlatforms.Windows)]
public void Socket_CreateUnixDomainSocket_Throws_OnWindows()
{
AssertExtensions.Throws<ArgumentNullException>("path", () => new UnixDomainSocketEndPoint(null));
AssertExtensions.Throws<ArgumentOutOfRangeException>("path", () => new UnixDomainSocketEndPoint(""));
AssertExtensions.Throws<ArgumentOutOfRangeException>("path", () => new UnixDomainSocketEndPoint(new string('s', 1000)));
Assert.Throws<PlatformNotSupportedException>(() => new UnixDomainSocketEndPoint("hello"));
}
private static string GetRandomNonExistingFilePath()
{
string result;
@@ -443,5 +438,34 @@ namespace System.Net.Sockets.Tests
return result;
}
private static bool PlatformSupportsUnixDomainSockets => s_platformSupportsUnixDomainSockets.Value;
private static bool PlatformDoesntSupportUnixDomainSockets => !s_platformSupportsUnixDomainSockets.Value;
private static readonly Lazy<bool> s_platformSupportsUnixDomainSockets = new Lazy<bool>(() =>
{
// All Unixes should support UDS. Some Windows will.
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
IntPtr s = socket((int)AddressFamily.Unix, (int)SocketType.Stream, (int)ProtocolType.Unspecified);
if (s == (IntPtr)(-1))
{
return false;
}
closesocket(s);
}
return true;
});
[DllImport("ws2_32.dll")]
internal static extern IntPtr socket(int af, int type, int protocol);
[DllImport("ws2_32.dll")]
internal static extern int closesocket(IntPtr socketHandle);
}
}

View File

@@ -68,5 +68,8 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>
</Project>

View File

@@ -17,8 +17,8 @@ namespace System.Net.Sockets.Tests
{
await OpenLoopbackConnectionAsync(async (client, server) =>
{
byte[] clientBuffer = new byte[1];
byte[] serverBuffer = new byte[1];
ReadOnlyMemory<byte> clientBuffer = new byte[1];
Memory<byte> serverBuffer = new byte[1];
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
@@ -39,8 +39,8 @@ namespace System.Net.Sockets.Tests
{
await OpenLoopbackConnectionAsync(async (client, server) =>
{
byte[] clientBuffer = new byte[1];
byte[] serverBuffer = new byte[1];
ReadOnlyMemory<byte> clientBuffer = new byte[1];
Memory<byte> serverBuffer = new byte[1];
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
long iters = Benchmark.InnerIterationCount;
@@ -48,7 +48,7 @@ namespace System.Net.Sockets.Tests
{
for (int i = 0; i < iters; i++)
{
Task r = server.ReceiveAsync(serverBuffer, SocketFlags.None);
ValueTask<int> r = server.ReceiveAsync(serverBuffer, SocketFlags.None);
await client.SendAsync(clientBuffer, SocketFlags.None);
await r;
}
@@ -57,30 +57,6 @@ namespace System.Net.Sockets.Tests
});
}
[Benchmark(InnerIterationCount = 1_000_000)]
[InlineData(16)]
public async Task ReceiveAsyncThenSendAsync_Task_Parallel(int numConnections)
{
byte[] clientBuffer = new byte[1];
byte[] serverBuffer = new byte[1];
foreach (BenchmarkIteration iteration in Benchmark.Iterations)
{
await OpenLoopbackConnectionAsync(async (client, server) =>
{
long iters = Benchmark.InnerIterationCount;
using (iteration.StartMeasurement())
{
for (int i = 0; i < iters; i++)
{
Task r = server.ReceiveAsync(serverBuffer, SocketFlags.None);
await client.SendAsync(clientBuffer, SocketFlags.None);
await r;
}
}
});
}
}
[Benchmark(InnerIterationCount = 10_000), MeasureGCAllocations]
public async Task SendAsyncThenReceiveAsync_SocketAsyncEventArgs()
{

View File

@@ -20,5 +20,8 @@
<Name>PerfRunner</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
</ItemGroup>
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
</Project>