From 57b774322bc5a8f81bbd805c69b87125632ee3c7 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 25 Jan 2021 17:19:56 +0100 Subject: [PATCH 01/12] use TempFile instead of FileCleanupTestBase --- .../tests/FunctionalTests/SendFile.cs | 46 ++++++++----------- .../System.Net.Sockets.Tests.csproj | 1 + 2 files changed, 19 insertions(+), 28 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index d138281212564..8c777305f6566 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -12,7 +12,7 @@ namespace System.Net.Sockets.Tests { - public class SendFileTest : FileCleanupTestBase + public class SendFileTest { public static IEnumerable SendFile_MemberData() { @@ -37,7 +37,7 @@ public static IEnumerable SendFileSync_MemberData() } } - private string CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) + private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) { // Create file to send var random = new Random(); @@ -56,8 +56,7 @@ private string CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] byte[] fileBuffer = new byte[fileSize]; random.NextBytes(fileBuffer); - string path = Path.GetTempFileName(); - File.WriteAllBytes(path, fileBuffer); + var tempFile = TempFile.Create(fileBuffer); checksum.Add(fileBuffer, 0, fileBuffer.Length); @@ -69,7 +68,7 @@ private string CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] checksum.Add(postBuffer, 0, postBuffer.Length); } - return path; + return tempFile; } [Fact] @@ -119,7 +118,7 @@ public async Task UdpConnection_ThrowsException(bool useAsync) byte[] preBuffer; byte[] postBuffer; Fletcher32 sentChecksum; - string filename = CreateFileToSend(size: 1, sendPreAndPostBuffers: false, out preBuffer, out postBuffer, out sentChecksum); + using TempFile tempFile = CreateFileToSend(size: 1, sendPreAndPostBuffers: false, out preBuffer, out postBuffer, out sentChecksum); using var client = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); using var listener = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp); @@ -129,15 +128,12 @@ public async Task UdpConnection_ThrowsException(bool useAsync) if (useAsync) { - await Assert.ThrowsAsync(() => Task.Factory.FromAsync(client.BeginSendFile, client.EndSendFile, filename, null)); + await Assert.ThrowsAsync(() => Task.Factory.FromAsync(client.BeginSendFile, client.EndSendFile, tempFile.Path, null)); } else { - Assert.Throws(() => client.SendFile(filename)); + Assert.Throws(() => client.SendFile(tempFile.Path)); } - - // Clean up the file we created - File.Delete(filename); } [Theory] @@ -233,8 +229,8 @@ public async Task SendFile_GreaterThan2GBFile_SendsAllBytes(bool useAsync) { const long FileLength = 100L + int.MaxValue; - string tmpFile = GetTestFilePath(); - using (FileStream fs = File.Create(tmpFile)) + using var tmpFile = TempFile.Create(); + using (FileStream fs = File.Create(tmpFile.Path)) { fs.SetLength(FileLength); } @@ -253,11 +249,11 @@ public async Task SendFile_GreaterThan2GBFile_SendsAllBytes(bool useAsync) { if (useAsync) { - await Task.Factory.FromAsync(server.BeginSendFile, server.EndSendFile, tmpFile, null); + await Task.Factory.FromAsync(server.BeginSendFile, server.EndSendFile, tmpFile.Path, null); } else { - server.SendFile(tmpFile); + server.SendFile(tmpFile.Path); } }), Task.Run(() => @@ -287,7 +283,7 @@ public void SendFile_Synchronous(IPAddress listenAt, bool sendPreAndPostBuffers, byte[] preBuffer; byte[] postBuffer; Fletcher32 sentChecksum; - string filename = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); + using TempFile tempFile = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); // Start server var server = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp); @@ -337,7 +333,7 @@ public void SendFile_Synchronous(IPAddress listenAt, bool sendPreAndPostBuffers, using (client) { - client.SendFile(filename, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); + client.SendFile(tempFile.Path, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); client.Shutdown(SocketShutdown.Send); } @@ -345,9 +341,6 @@ public void SendFile_Synchronous(IPAddress listenAt, bool sendPreAndPostBuffers, Assert.Equal(bytesToSend, bytesReceived); Assert.Equal(sentChecksum.Sum, receivedChecksum.Sum); - - // Clean up the file we created - File.Delete(filename); } [Fact] @@ -365,13 +358,13 @@ await RetryHelper.ExecuteAsync(async () => Task socketOperation = Task.Run(() => { // Create a large file that will cause SendFile to block until the peer starts reading. - string filename = GetTestFilePath(); - using (var fs = new FileStream(filename, FileMode.CreateNew, FileAccess.Write)) + using var tempFile = TempFile.Create(); + using (var fs = new FileStream(tempFile.Path, FileMode.CreateNew, FileAccess.Write)) { fs.SetLength(20 * 1024 * 1024 /* 20MB */); } - socket1.SendFile(filename); + socket1.SendFile(tempFile.Path); }); // Wait a little so the operation is started. @@ -433,7 +426,7 @@ public async Task SendFile_APM(IPAddress listenAt, bool sendPreAndPostBuffers, i // Create file to send byte[] preBuffer, postBuffer; Fletcher32 sentChecksum; - string filename = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); + using TempFile tempFile = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); // Start server using (var listener = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) @@ -463,7 +456,7 @@ public async Task SendFile_APM(IPAddress listenAt, bool sendPreAndPostBuffers, i { await client.ConnectAsync(listener.LocalEndPoint); await Task.Factory.FromAsync( - (callback, state) => client.BeginSendFile(filename, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread, callback, state), + (callback, state) => client.BeginSendFile(tempFile.Path, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread, callback, state), iar => client.EndSendFile(iar), null); client.Shutdown(SocketShutdown.Send); @@ -477,9 +470,6 @@ await Task.Factory.FromAsync( Assert.Equal(bytesToSend, bytesReceived); Assert.Equal(sentChecksum.Sum, receivedChecksum.Sum); } - - // Clean up the file we created - File.Delete(filename); } } } 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 7ce628db90aae..74eb8919b17c8 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 @@ -98,6 +98,7 @@ + From f115490ce57b377592a229a6033d363955224ae0 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Mon, 25 Jan 2021 19:44:18 +0100 Subject: [PATCH 02/12] most SendFile tests refactored --- .../tests/FunctionalTests/SendFile.cs | 275 ++++++++++-------- .../tests/FunctionalTests/SocketTestHelper.cs | 29 +- 2 files changed, 179 insertions(+), 125 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index 8c777305f6566..a4a8ae0da7ecf 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -8,12 +8,17 @@ using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; using Xunit.Sdk; namespace System.Net.Sockets.Tests { - public class SendFileTest + public abstract class SendFileBase : SocketTestHelperBase where T : SocketHelperBase, new() { + protected SendFileBase(ITestOutputHelper output) : base(output) + { + } + public static IEnumerable SendFile_MemberData() { foreach (IPAddress listenAt in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback }) @@ -37,82 +42,29 @@ public static IEnumerable SendFileSync_MemberData() } } - private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) - { - // Create file to send - var random = new Random(); - int fileSize = sendPreAndPostBuffers ? size - 512 : size; - - checksum = new Fletcher32(); - - preBuffer = null; - if (sendPreAndPostBuffers) - { - preBuffer = new byte[256]; - random.NextBytes(preBuffer); - checksum.Add(preBuffer, 0, preBuffer.Length); - } - - byte[] fileBuffer = new byte[fileSize]; - random.NextBytes(fileBuffer); - - var tempFile = TempFile.Create(fileBuffer); - - checksum.Add(fileBuffer, 0, fileBuffer.Length); - - postBuffer = null; - if (sendPreAndPostBuffers) - { - postBuffer = new byte[256]; - random.NextBytes(postBuffer); - checksum.Add(postBuffer, 0, postBuffer.Length); - } - - return tempFile; - } - [Fact] - public void Disposed_ThrowsException() + public async Task Disposed_ThrowsException() { - using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - { - s.Dispose(); - Assert.Throws(() => s.SendFile(null)); - Assert.Throws(() => s.SendFile(null, null, null, TransmitFileOptions.UseDefaultWorkerThread)); - Assert.Throws(() => s.SendFile(null, ReadOnlySpan.Empty, ReadOnlySpan.Empty, TransmitFileOptions.UseDefaultWorkerThread)); - Assert.Throws(() => s.BeginSendFile(null, null, null)); - Assert.Throws(() => s.BeginSendFile(null, null, null, TransmitFileOptions.UseDefaultWorkerThread, null, null)); - Assert.Throws(() => s.EndSendFile(null)); - } + using Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + s.Dispose(); + await Assert.ThrowsAsync(() => SendFileAsync(s, null)); + await Assert.ThrowsAsync(() => SendFileAsync(s, null, null, null, TransmitFileOptions.UseDefaultWorkerThread)); } - [Fact] - public void EndSendFile_NullAsyncResult_Throws() - { - using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - { - Assert.Throws(() => s.EndSendFile(null)); - } - } [Fact] - public void NotConnected_ThrowsException() + public async Task NotConnected_ThrowsException() { - using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - { - Assert.Throws(() => s.SendFile(null)); - Assert.Throws(() => s.SendFile(null, null, null, TransmitFileOptions.UseDefaultWorkerThread)); - Assert.Throws(() => s.SendFile(null, ReadOnlySpan.Empty, ReadOnlySpan.Empty, TransmitFileOptions.UseDefaultWorkerThread)); - Assert.Throws(() => s.BeginSendFile(null, null, null)); - Assert.Throws(() => s.BeginSendFile(null, null, null, TransmitFileOptions.UseDefaultWorkerThread, null, null)); - } + using Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + + await Assert.ThrowsAsync(() => SendFileAsync(s, null)); + await Assert.ThrowsAsync(() => SendFileAsync(s, null, null, null, TransmitFileOptions.UseDefaultWorkerThread)); } - [ConditionalTheory] + + [Fact] [PlatformSpecific(TestPlatforms.Windows)] - [InlineData(true)] - [InlineData(false)] - public async Task UdpConnection_ThrowsException(bool useAsync) + public async Task UdpConnection_ThrowsException() { // Create file to send byte[] preBuffer; @@ -126,26 +78,16 @@ public async Task UdpConnection_ThrowsException(bool useAsync) client.Connect(listener.LocalEndPoint); - if (useAsync) - { - await Assert.ThrowsAsync(() => Task.Factory.FromAsync(client.BeginSendFile, client.EndSendFile, tempFile.Path, null)); - } - else - { - Assert.Throws(() => client.SendFile(tempFile.Path)); - } + await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path)); + await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path, Array.Empty(), Array.Empty(), TransmitFileOptions.UseDefaultWorkerThread)); } [Theory] - [InlineData(false, false, false)] - [InlineData(false, false, true)] - [InlineData(false, true, false)] - [InlineData(false, true, true)] - [InlineData(true, false, false)] - [InlineData(true, false, true)] - [InlineData(true, true, false)] - [InlineData(true, true, true)] - public async Task SendFile_NoFile_Succeeds(bool useAsync, bool usePreBuffer, bool usePostBuffer) + [InlineData(false, false)] + [InlineData(false, true)] + [InlineData(true, false)] + [InlineData(true, true)] + public async Task NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) { using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); using var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -155,28 +97,14 @@ public async Task SendFile_NoFile_Succeeds(bool useAsync, bool usePreBuffer, boo client.Connect(listener.LocalEndPoint); using Socket server = listener.Accept(); - if (useAsync) - { - await Task.Factory.FromAsync(server.BeginSendFile, server.EndSendFile, null, null); - } - else - { - server.SendFile(null); - } + await SendFileAsync(server, null); Assert.Equal(0, client.Available); byte[] preBuffer = usePreBuffer ? new byte[1] : null; byte[] postBuffer = usePostBuffer ? new byte[1] : null; int bytesExpected = (usePreBuffer ? 1 : 0) + (usePostBuffer ? 1 : 0); - if (useAsync) - { - await Task.Factory.FromAsync((c, s) => server.BeginSendFile(null, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread, c, s), server.EndSendFile, null); - } - else - { - server.SendFile(null, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); - } + await SendFileAsync(server, null, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); byte[] receiveBuffer = new byte[1]; for (int i = 0; i < bytesExpected; i++) @@ -187,37 +115,98 @@ public async Task SendFile_NoFile_Succeeds(bool useAsync, bool usePreBuffer, boo Assert.Equal(0, client.Available); } - [Theory] - [InlineData(false, false)] - [InlineData(false, true)] - [InlineData(true, false)] - [InlineData(true, true)] - public void SendFileSpan_NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) + private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) { - using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - using var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - listener.BindToAnonymousPort(IPAddress.Loopback); - listener.Listen(1); + // Create file to send + var random = new Random(); + int fileSize = sendPreAndPostBuffers ? size - 512 : size; - client.Connect(listener.LocalEndPoint); - using Socket server = listener.Accept(); + checksum = new Fletcher32(); - server.SendFile(null); - Assert.Equal(0, client.Available); + preBuffer = null; + if (sendPreAndPostBuffers) + { + preBuffer = new byte[256]; + random.NextBytes(preBuffer); + checksum.Add(preBuffer, 0, preBuffer.Length); + } - byte[] preBuffer = usePreBuffer ? new byte[1] : null; - byte[] postBuffer = usePostBuffer ? new byte[1] : null; - int bytesExpected = (usePreBuffer ? 1 : 0) + (usePostBuffer ? 1 : 0); + byte[] fileBuffer = new byte[fileSize]; + random.NextBytes(fileBuffer); - server.SendFile(null, preBuffer.AsSpan(), postBuffer.AsSpan(), TransmitFileOptions.UseDefaultWorkerThread); + var tempFile = TempFile.Create(fileBuffer); - byte[] receiveBuffer = new byte[1]; - for (int i = 0; i < bytesExpected; i++) + checksum.Add(fileBuffer, 0, fileBuffer.Length); + + postBuffer = null; + if (sendPreAndPostBuffers) { - Assert.Equal(1, client.Receive(receiveBuffer)); + postBuffer = new byte[256]; + random.NextBytes(postBuffer); + checksum.Add(postBuffer, 0, postBuffer.Length); } - Assert.Equal(0, client.Available); + return tempFile; + } + } + + public class SendFileTest_old + { + public static IEnumerable SendFile_MemberData() + { + foreach (IPAddress listenAt in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback }) + { + foreach (bool sendPreAndPostBuffers in new[] { true, false }) + { + foreach (int bytesToSend in new[] { 512, 1024, 12345678 }) + { + yield return new object[] { listenAt, sendPreAndPostBuffers, bytesToSend }; + } + } + } + } + + public static IEnumerable SendFileSync_MemberData() + { + foreach (object[] memberData in SendFile_MemberData()) + { + yield return memberData.Concat(new object[] { true }).ToArray(); + yield return memberData.Concat(new object[] { false }).ToArray(); + } + } + + private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) + { + // Create file to send + var random = new Random(); + int fileSize = sendPreAndPostBuffers ? size - 512 : size; + + checksum = new Fletcher32(); + + preBuffer = null; + if (sendPreAndPostBuffers) + { + preBuffer = new byte[256]; + random.NextBytes(preBuffer); + checksum.Add(preBuffer, 0, preBuffer.Length); + } + + byte[] fileBuffer = new byte[fileSize]; + random.NextBytes(fileBuffer); + + var tempFile = TempFile.Create(fileBuffer); + + checksum.Add(fileBuffer, 0, fileBuffer.Length); + + postBuffer = null; + if (sendPreAndPostBuffers) + { + postBuffer = new byte[256]; + random.NextBytes(postBuffer); + checksum.Add(postBuffer, 0, postBuffer.Length); + } + + return tempFile; } [ActiveIssue("https://github.com/dotnet/runtime/issues/42534", TestPlatforms.Windows)] @@ -472,4 +461,46 @@ await Task.Factory.FromAsync( } } } + + public sealed class SendFile_SyncSpan : SendFileBase + { + public SendFile_SyncSpan(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_SyncSpanForceNonBlocking : SendFileBase + { + public SendFile_SyncSpanForceNonBlocking(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_ArraySync : SendFileBase + { + public SendFile_ArraySync(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_SyncForceNonBlocking : SendFileBase + { + public SendFile_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_Apm : SendFileBase + { + public SendFile_Apm(ITestOutputHelper output) : base(output) { } + + [Fact] + public void IndividualBeginEndMethods_Disposed_ThrowsObjectDisposedException() + { + using Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + s.Dispose(); + Assert.Throws(() => s.BeginSendFile(null, null, null)); + Assert.Throws(() => s.BeginSendFile(null, null, null, TransmitFileOptions.UseDefaultWorkerThread, null, null)); + Assert.Throws(() => s.EndSendFile(null)); + } + + [Fact] + public void EndSendFile_NullAsyncResult_Throws() + { + using Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + Assert.Throws(() => s.EndSendFile(null)); + } + } } diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs index 93e050059ca71..f2822d470b975 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs @@ -33,6 +33,8 @@ public abstract Task ReceiveMessageFromAsync( public abstract Task SendAsync(Socket s, ArraySegment buffer); public abstract Task SendAsync(Socket s, IList> bufferList); public abstract Task SendToAsync(Socket s, ArraySegment buffer, EndPoint endpoint); + public abstract Task SendFileAsync(Socket s, string fileName); + public abstract Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags); public virtual bool GuaranteedSendOrdering => true; public virtual bool ValidatesArrayArguments => true; public virtual bool UsesSync => false; @@ -42,6 +44,7 @@ public abstract Task ReceiveMessageFromAsync( public virtual bool SupportsMultiConnect => true; public virtual bool SupportsAcceptIntoExistingSocket => true; public virtual bool SupportsAcceptReceive => false; + public virtual bool SupportsSendFileSlicing => false; public virtual void Listen(Socket s, int backlog) { s.Listen(backlog); } public virtual void ConfigureNonBlocking(Socket s) { } } @@ -90,7 +93,9 @@ public override Task SendAsync(Socket s, IList> bufferLi Task.Run(() => s.Send(bufferList, SocketFlags.None)); public override Task SendToAsync(Socket s, ArraySegment buffer, EndPoint endPoint) => Task.Run(() => s.SendTo(buffer.Array, buffer.Offset, buffer.Count, SocketFlags.None, endPoint)); - + public override Task SendFileAsync(Socket s, string fileName) => Task.Run(() => s.SendFile(fileName)); + public override Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => + Task.Run(() => s.SendFile(fileName, preBuffer.Array, postBuffer.Array, flags)); public override bool GuaranteedSendOrdering => false; public override bool UsesSync => true; public override bool ConnectAfterDisconnectResultsInInvalidOperationException => true; @@ -191,7 +196,14 @@ public override Task SendToAsync(Socket s, ArraySegment buffer, EndPo Task.Factory.FromAsync( (callback, state) => s.BeginSendTo(buffer.Array, buffer.Offset, buffer.Count, SocketFlags.None, endPoint, callback, state), s.EndSendTo, null); - + public override Task SendFileAsync(Socket s, string fileName) => + Task.Factory.FromAsync( + (callback, state) => s.BeginSendFile(fileName, callback, state), + s.EndSendTo, null); + public override Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => + Task.Factory.FromAsync( + (callback, state) => s.BeginSendFile(fileName, preBuffer.Array, postBuffer.Array, flags, callback, state), + s.EndSendTo, null); public override bool UsesApm => true; } @@ -221,6 +233,8 @@ public override Task SendAsync(Socket s, IList> bufferLi s.SendAsync(bufferList, SocketFlags.None); public override Task SendToAsync(Socket s, ArraySegment buffer, EndPoint endPoint) => s.SendToAsync(buffer, SocketFlags.None, endPoint); + public override Task SendFileAsync(Socket s, string fileName) => throw new NotSupportedException(); + public override Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => throw new NotSupportedException(); } // Same as above, but call the CancellationToken overloads where possible @@ -253,6 +267,8 @@ public override Task SendAsync(Socket s, IList> bufferLi s.SendAsync(bufferList, SocketFlags.None); public override Task SendToAsync(Socket s, ArraySegment buffer, EndPoint endPoint) => s.SendToAsync(buffer, SocketFlags.None, endPoint); + public override Task SendFileAsync(Socket s, string fileName) => throw new NotSupportedException(); + public override Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => throw new NotSupportedException(); } public sealed class SocketHelperEap : SocketHelperBase @@ -342,7 +358,8 @@ public override Task SendToAsync(Socket s, ArraySegment buffer, EndPo e.RemoteEndPoint = endPoint; return s.SendToAsync(e); }); - + public override Task SendFileAsync(Socket s, string fileName) => throw new NotSupportedException(); + public override Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => throw new NotSupportedException(); private static Task InvokeAsync( Socket s, Func getResult, @@ -397,6 +414,9 @@ public Task ReceiveMessageFromAsync(Socket s, Ar public Task SendAsync(Socket s, ArraySegment buffer) => _socketHelper.SendAsync(s, buffer); public Task SendAsync(Socket s, IList> bufferList) => _socketHelper.SendAsync(s, bufferList); public Task SendToAsync(Socket s, ArraySegment buffer, EndPoint endpoint) => _socketHelper.SendToAsync(s, buffer, endpoint); + public Task SendFileAsync(Socket s, string fileName) => _socketHelper.SendFileAsync(s, fileName); + public Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => + _socketHelper.SendFileAsync(s, fileName, preBuffer, postBuffer, flags); public bool GuaranteedSendOrdering => _socketHelper.GuaranteedSendOrdering; public bool ValidatesArrayArguments => _socketHelper.ValidatesArrayArguments; public bool UsesSync => _socketHelper.UsesSync; @@ -417,7 +437,10 @@ public override Task ReceiveAsync(Socket s, ArraySegment buffer) => Task.Run(() => s.Receive((Span)buffer, SocketFlags.None)); public override Task SendAsync(Socket s, ArraySegment buffer) => Task.Run(() => s.Send((ReadOnlySpan)buffer, SocketFlags.None)); + public override Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => + Task.Run(() => s.SendFile(fileName, preBuffer, postBuffer, flags)); public override bool UsesSync => true; + public override bool SupportsSendFileSlicing => true; } public sealed class SocketHelperSpanSyncForceNonBlocking : SocketHelperSpanSync From 5a0187023b6d56fde61fa2fa692aaf2407575ffc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 17:58:34 +0100 Subject: [PATCH 03/12] change UdpConnection_ThrowsException because of #47472 --- .../tests/FunctionalTests/SendFile.cs | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index a4a8ae0da7ecf..c41b1d60c0c65 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -62,9 +62,11 @@ public async Task NotConnected_ThrowsException() } - [Fact] + [Theory] + [InlineData(false)] + [InlineData(true)] [PlatformSpecific(TestPlatforms.Windows)] - public async Task UdpConnection_ThrowsException() + public async Task UdpConnection_ThrowsException(bool usePreAndPostbufferOverload) { // Create file to send byte[] preBuffer; @@ -78,8 +80,14 @@ public async Task UdpConnection_ThrowsException() client.Connect(listener.LocalEndPoint); - await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path)); - await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path, Array.Empty(), Array.Empty(), TransmitFileOptions.UseDefaultWorkerThread)); + if (usePreAndPostbufferOverload) + { + await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path, Array.Empty(), Array.Empty(), TransmitFileOptions.UseDefaultWorkerThread)); + } + else + { + await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path)); + } } [Theory] From a858a4c64b074dfde699a68e8803f2a2c2828e55 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 18:06:56 +0100 Subject: [PATCH 04/12] fix SocketHelperApm.SendFileAsync --- .../tests/FunctionalTests/SocketTestHelper.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs index f2822d470b975..3e6740111b0ca 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs @@ -199,11 +199,11 @@ public override Task SendToAsync(Socket s, ArraySegment buffer, EndPo public override Task SendFileAsync(Socket s, string fileName) => Task.Factory.FromAsync( (callback, state) => s.BeginSendFile(fileName, callback, state), - s.EndSendTo, null); + s.EndSendFile, null); public override Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffer, ArraySegment postBuffer, TransmitFileOptions flags) => Task.Factory.FromAsync( (callback, state) => s.BeginSendFile(fileName, preBuffer.Array, postBuffer.Array, flags, callback, state), - s.EndSendTo, null); + s.EndSendFile, null); public override bool UsesApm => true; } From 7ecc497cf1ad9608f8b7f4f286ef765c222eb907 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 18:27:48 +0100 Subject: [PATCH 05/12] IncludeFile_Success --- .../tests/FunctionalTests/SendFile.cs | 314 +++++++----------- 1 file changed, 112 insertions(+), 202 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index c41b1d60c0c65..1f21cce556113 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -19,29 +19,6 @@ protected SendFileBase(ITestOutputHelper output) : base(output) { } - public static IEnumerable SendFile_MemberData() - { - foreach (IPAddress listenAt in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback }) - { - foreach (bool sendPreAndPostBuffers in new[] { true, false }) - { - foreach (int bytesToSend in new[] { 512, 1024, 12345678 }) - { - yield return new object[] { listenAt, sendPreAndPostBuffers, bytesToSend }; - } - } - } - } - - public static IEnumerable SendFileSync_MemberData() - { - foreach (object[] memberData in SendFile_MemberData()) - { - yield return memberData.Concat(new object[] { true }).ToArray(); - yield return memberData.Concat(new object[] { false }).ToArray(); - } - } - [Fact] public async Task Disposed_ThrowsException() { @@ -90,6 +67,79 @@ public async Task UdpConnection_ThrowsException(bool usePreAndPostbufferOverload } } + public static IEnumerable SendFile_MemberData() + { + foreach (IPAddress listenAt in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback }) + { + foreach (bool sendPreAndPostBuffers in new[] { true, false }) + { + foreach (int bytesToSend in new[] { 512, 1024, 12345678 }) + { + yield return new object[] { listenAt, sendPreAndPostBuffers, bytesToSend }; + } + } + } + } + + [Theory] + [MemberData(nameof(SendFile_MemberData))] + public async Task IncludeFile_Success(IPAddress listenAt, bool sendPreAndPostBuffers, int bytesToSend) + { + const int ListenBacklog = 1; + const int TestTimeout = 30000; + + // Create file to send + byte[] preBuffer; + byte[] postBuffer; + Fletcher32 sentChecksum; + using TempFile tempFile = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); + + // Start server + var server = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp); + server.BindToAnonymousPort(listenAt); + Listen(server, ListenBacklog); // Configures NonBlocking behavior + + int bytesReceived = 0; + var receivedChecksum = new Fletcher32(); + var serverTask = Task.Run(() => + { + using (server) + { + Socket remote = server.Accept(); + Assert.NotNull(remote); + + using (remote) + { + var recvBuffer = new byte[256]; + while (true) + { + int received = remote.Receive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None); + if (received == 0) + { + break; + } + + bytesReceived += received; + receivedChecksum.Add(recvBuffer, 0, received); + } + } + } + }); + + // Run client + EndPoint serverEndpoint = server.LocalEndPoint; + using (var client = new Socket(serverEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) + { + await ConnectAsync(client, serverEndpoint); // Configures NonBlocking behavior + await SendFileAsync(client, tempFile.Path, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); + client.Shutdown(SocketShutdown.Send); + } + + await serverTask.TimeoutAfter(TestTimeout); + Assert.Equal(bytesToSend, bytesReceived); + Assert.Equal(sentChecksum.Sum, receivedChecksum.Sum); + } + [Theory] [InlineData(false, false)] [InlineData(false, true)] @@ -123,6 +173,45 @@ public async Task NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) Assert.Equal(0, client.Available); } + [ActiveIssue("https://github.com/dotnet/runtime/issues/42534", TestPlatforms.Windows)] + [OuterLoop("Creates and sends a file several gigabytes long")] + [Fact] + public async Task GreaterThan2GBFile_SendsAllBytes() + { + const long FileLength = 100L + int.MaxValue; + + using var tmpFile = TempFile.Create(); + using (FileStream fs = File.Create(tmpFile.Path)) + { + fs.SetLength(FileLength); + } + + using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + using var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); + listener.BindToAnonymousPort(IPAddress.Loopback); + listener.Listen(1); + + client.Connect(listener.LocalEndPoint); + using Socket server = listener.Accept(); + + await new Task[] + { + SendFileAsync(server, tmpFile.Path), + Task.Run(() => + { + byte[] buffer = new byte[100_000]; + long count = 0; + while (count < FileLength) + { + int received = client.Receive(buffer); + Assert.NotEqual(0, received); + count += received; + } + Assert.Equal(0, client.Available); + }) + }.WhenAllOrAnyFailed(); + } + private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) { // Create file to send @@ -217,129 +306,6 @@ private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte return tempFile; } - [ActiveIssue("https://github.com/dotnet/runtime/issues/42534", TestPlatforms.Windows)] - [OuterLoop("Creates and sends a file several gigabytes long")] - [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task SendFile_GreaterThan2GBFile_SendsAllBytes(bool useAsync) - { - const long FileLength = 100L + int.MaxValue; - - using var tmpFile = TempFile.Create(); - using (FileStream fs = File.Create(tmpFile.Path)) - { - fs.SetLength(FileLength); - } - - using var client = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - using var listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); - listener.BindToAnonymousPort(IPAddress.Loopback); - listener.Listen(1); - - client.Connect(listener.LocalEndPoint); - using Socket server = listener.Accept(); - - await new Task[] - { - Task.Run(async () => - { - if (useAsync) - { - await Task.Factory.FromAsync(server.BeginSendFile, server.EndSendFile, tmpFile.Path, null); - } - else - { - server.SendFile(tmpFile.Path); - } - }), - Task.Run(() => - { - byte[] buffer = new byte[100_000]; - long count = 0; - while (count < FileLength) - { - int received = client.Receive(buffer); - Assert.NotEqual(0, received); - count += received; - } - Assert.Equal(0, client.Available); - }) - }.WhenAllOrAnyFailed(); - } - - [OuterLoop] - [Theory] - [MemberData(nameof(SendFileSync_MemberData))] - public void SendFile_Synchronous(IPAddress listenAt, bool sendPreAndPostBuffers, int bytesToSend, bool forceNonBlocking) - { - const int ListenBacklog = 1; - const int TestTimeout = 30000; - - // Create file to send - byte[] preBuffer; - byte[] postBuffer; - Fletcher32 sentChecksum; - using TempFile tempFile = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); - - // Start server - var server = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - server.BindToAnonymousPort(listenAt); - - server.Listen(ListenBacklog); - - server.ForceNonBlocking(forceNonBlocking); - - int bytesReceived = 0; - var receivedChecksum = new Fletcher32(); - var serverThread = new Thread(() => - { - using (server) - { - Socket remote = server.Accept(); - Assert.NotNull(remote); - - remote.ForceNonBlocking(forceNonBlocking); - - using (remote) - { - var recvBuffer = new byte[256]; - while (true) - { - int received = remote.Receive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None); - if (received == 0) - { - break; - } - - bytesReceived += received; - receivedChecksum.Add(recvBuffer, 0, received); - } - } - } - }); - serverThread.Start(); - - // Run client - EndPoint clientEndpoint = server.LocalEndPoint; - var client = new Socket(clientEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp); - - client.ForceNonBlocking(forceNonBlocking); - - client.Connect(clientEndpoint); - - using (client) - { - client.SendFile(tempFile.Path, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); - client.Shutdown(SocketShutdown.Send); - } - - Assert.True(serverThread.Join(TestTimeout), "Completed within allowed time"); - - Assert.Equal(bytesToSend, bytesReceived); - Assert.Equal(sentChecksum.Sum, receivedChecksum.Sum); - } - [Fact] public async Task SyncSendFileGetsCanceledByDispose() { @@ -412,62 +378,6 @@ await RetryHelper.ExecuteAsync(async () => } }, maxAttempts: 10, retryWhen: e => e is XunitException); } - - [OuterLoop] - [Theory] - [MemberData(nameof(SendFile_MemberData))] - public async Task SendFile_APM(IPAddress listenAt, bool sendPreAndPostBuffers, int bytesToSend) - { - const int ListenBacklog = 1, TestTimeout = 30000; - - // Create file to send - byte[] preBuffer, postBuffer; - Fletcher32 sentChecksum; - using TempFile tempFile = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); - - // Start server - using (var listener = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) - { - listener.BindToAnonymousPort(listenAt); - listener.Listen(ListenBacklog); - - int bytesReceived = 0; - var receivedChecksum = new Fletcher32(); - - Task serverTask = Task.Run(async () => - { - using (var serverStream = new NetworkStream(await listener.AcceptAsync(), ownsSocket: true)) - { - var buffer = new byte[256]; - int bytesRead; - while ((bytesRead = await serverStream.ReadAsync(buffer, 0, buffer.Length)) != 0) - { - bytesReceived += bytesRead; - receivedChecksum.Add(buffer, 0, bytesRead); - } - } - }); - Task clientTask = Task.Run(async () => - { - using (var client = new Socket(listener.LocalEndPoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) - { - await client.ConnectAsync(listener.LocalEndPoint); - await Task.Factory.FromAsync( - (callback, state) => client.BeginSendFile(tempFile.Path, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread, callback, state), - iar => client.EndSendFile(iar), - null); - client.Shutdown(SocketShutdown.Send); - } - }); - - // Wait for the tasks to complete - await (new[] { serverTask, clientTask }).WhenAllOrAnyFailed(TestTimeout); - - // Validate the results - Assert.Equal(bytesToSend, bytesReceived); - Assert.Equal(sentChecksum.Sum, receivedChecksum.Sum); - } - } } public sealed class SendFile_SyncSpan : SendFileBase From e7c11881952ef0ac621faf39b4aa1571156900bb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 18:36:37 +0100 Subject: [PATCH 06/12] SendFileGetsCanceledByDispose --- .../tests/FunctionalTests/SendFile.cs | 158 ++++++++++-------- 1 file changed, 85 insertions(+), 73 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index 1f21cce556113..f71adcdf9d058 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -212,6 +212,91 @@ public async Task GreaterThan2GBFile_SendsAllBytes() }.WhenAllOrAnyFailed(); } + [Fact] + public async Task SendFileGetsCanceledByDispose() + { + // We try this a couple of times to deal with a timing race: if the Dispose happens + // before the operation is started, the peer won't see a ConnectionReset SocketException and we won't + // see a SocketException either. + int msDelay = 100; + await RetryHelper.ExecuteAsync(async () => + { + (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair(); + using (socket2) + { + Task socketOperation = Task.Run(async () => + { + // Create a large file that will cause SendFile to block until the peer starts reading. + using var tempFile = TempFile.Create(); + using (var fs = new FileStream(tempFile.Path, FileMode.CreateNew, FileAccess.Write)) + { + fs.SetLength(20 * 1024 * 1024 /* 20MB */); + } + + await SendFileAsync(socket1, tempFile.Path); + }); + + // Wait a little so the operation is started. + await Task.Delay(msDelay); + msDelay *= 2; + Task disposeTask = Task.Run(() => socket1.Dispose()); + + await Task.WhenAny(disposeTask, socketOperation).TimeoutAfter(30000); + await disposeTask; + + SocketError? localSocketError = null; + bool thrownDisposed = false; + try + { + await socketOperation; + } + catch (SocketException se) + { + localSocketError = se.SocketErrorCode; + } + catch (ObjectDisposedException) + { + thrownDisposed = true; + } + + if (UsesSync) + { + Assert.Equal(SocketError.ConnectionAborted, localSocketError); + } + else + { + Assert.True(thrownDisposed); + } + + + // On OSX, we're unable to unblock the on-going socket operations and + // perform an abortive close. + if (!(UsesSync && PlatformDetection.IsOSXLike)) + { + SocketError? peerSocketError = null; + var receiveBuffer = new byte[4096]; + while (true) + { + try + { + int received = socket2.Receive(receiveBuffer); + if (received == 0) + { + break; + } + } + catch (SocketException se) + { + peerSocketError = se.SocketErrorCode; + break; + } + } + Assert.Equal(SocketError.ConnectionReset, peerSocketError); + } + } + }, maxAttempts: 10, retryWhen: e => e is XunitException); + } + private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) { // Create file to send @@ -305,79 +390,6 @@ private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte return tempFile; } - - [Fact] - public async Task SyncSendFileGetsCanceledByDispose() - { - // We try this a couple of times to deal with a timing race: if the Dispose happens - // before the operation is started, the peer won't see a ConnectionReset SocketException and we won't - // see a SocketException either. - int msDelay = 100; - await RetryHelper.ExecuteAsync(async () => - { - (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair(); - using (socket2) - { - Task socketOperation = Task.Run(() => - { - // Create a large file that will cause SendFile to block until the peer starts reading. - using var tempFile = TempFile.Create(); - using (var fs = new FileStream(tempFile.Path, FileMode.CreateNew, FileAccess.Write)) - { - fs.SetLength(20 * 1024 * 1024 /* 20MB */); - } - - socket1.SendFile(tempFile.Path); - }); - - // Wait a little so the operation is started. - await Task.Delay(msDelay); - msDelay *= 2; - Task disposeTask = Task.Run(() => socket1.Dispose()); - - await Task.WhenAny(disposeTask, socketOperation).TimeoutAfter(30000); - await disposeTask; - - SocketError? localSocketError = null; - try - { - await socketOperation; - } - catch (SocketException se) - { - localSocketError = se.SocketErrorCode; - } - catch (ObjectDisposedException) - { } - Assert.Equal(SocketError.ConnectionAborted, localSocketError); - - // On OSX, we're unable to unblock the on-going socket operations and - // perform an abortive close. - if (!PlatformDetection.IsOSXLike) - { - SocketError? peerSocketError = null; - var receiveBuffer = new byte[4096]; - while (true) - { - try - { - int received = socket2.Receive(receiveBuffer); - if (received == 0) - { - break; - } - } - catch (SocketException se) - { - peerSocketError = se.SocketErrorCode; - break; - } - } - Assert.Equal(SocketError.ConnectionReset, peerSocketError); - } - } - }, maxAttempts: 10, retryWhen: e => e is XunitException); - } } public sealed class SendFile_SyncSpan : SendFileBase From 1d8dbcf955067a79da5785089c8fd78bd01cc1b5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 18:37:21 +0100 Subject: [PATCH 07/12] delete the old test class --- .../tests/FunctionalTests/SendFile.cs | 60 ------------------- 1 file changed, 60 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index f71adcdf9d058..cd6a0d6be4217 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -332,66 +332,6 @@ private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte } } - public class SendFileTest_old - { - public static IEnumerable SendFile_MemberData() - { - foreach (IPAddress listenAt in new[] { IPAddress.Loopback, IPAddress.IPv6Loopback }) - { - foreach (bool sendPreAndPostBuffers in new[] { true, false }) - { - foreach (int bytesToSend in new[] { 512, 1024, 12345678 }) - { - yield return new object[] { listenAt, sendPreAndPostBuffers, bytesToSend }; - } - } - } - } - - public static IEnumerable SendFileSync_MemberData() - { - foreach (object[] memberData in SendFile_MemberData()) - { - yield return memberData.Concat(new object[] { true }).ToArray(); - yield return memberData.Concat(new object[] { false }).ToArray(); - } - } - - private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) - { - // Create file to send - var random = new Random(); - int fileSize = sendPreAndPostBuffers ? size - 512 : size; - - checksum = new Fletcher32(); - - preBuffer = null; - if (sendPreAndPostBuffers) - { - preBuffer = new byte[256]; - random.NextBytes(preBuffer); - checksum.Add(preBuffer, 0, preBuffer.Length); - } - - byte[] fileBuffer = new byte[fileSize]; - random.NextBytes(fileBuffer); - - var tempFile = TempFile.Create(fileBuffer); - - checksum.Add(fileBuffer, 0, fileBuffer.Length); - - postBuffer = null; - if (sendPreAndPostBuffers) - { - postBuffer = new byte[256]; - random.NextBytes(postBuffer); - checksum.Add(postBuffer, 0, postBuffer.Length); - } - - return tempFile; - } - } - public sealed class SendFile_SyncSpan : SendFileBase { public SendFile_SyncSpan(ITestOutputHelper output) : base(output) { } From 8ad918cb5a4bde91e8349adde6514db1137bd3fa Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 19:05:10 +0100 Subject: [PATCH 08/12] FileDoesNotExist_ThrowsFileNotFoundException --- .../tests/FunctionalTests/SendFile.cs | 29 +++++++++++++++++-- 1 file changed, 26 insertions(+), 3 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index cd6a0d6be4217..4e3dbe78fe2db 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -30,7 +30,7 @@ public async Task Disposed_ThrowsException() [Fact] - public async Task NotConnected_ThrowsException() + public async Task NotConnected_ThrowsNotSupportedException() { using Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); @@ -38,6 +38,27 @@ public async Task NotConnected_ThrowsException() await Assert.ThrowsAsync(() => SendFileAsync(s, null, null, null, TransmitFileOptions.UseDefaultWorkerThread)); } + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task FileDoesNotExist_ThrowsFileNotFoundException(bool useOverloadWithBuffers) + { + string doesNotExist = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + (Socket client, Socket server) = SocketTestExtensions.CreateConnectedSocketPair(); + + using (client) + using (server) + { + if (!useOverloadWithBuffers) + { + await Assert.ThrowsAsync(() => SendFileAsync(client, doesNotExist)); + } + else + { + await Assert.ThrowsAsync(() => SendFileAsync(client, doesNotExist, null, null, TransmitFileOptions.UseDefaultWorkerThread)); + } + } + } [Theory] [InlineData(false)] @@ -57,14 +78,16 @@ public async Task UdpConnection_ThrowsException(bool usePreAndPostbufferOverload client.Connect(listener.LocalEndPoint); + SocketException ex; if (usePreAndPostbufferOverload) { - await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path, Array.Empty(), Array.Empty(), TransmitFileOptions.UseDefaultWorkerThread)); + ex = await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path, Array.Empty(), Array.Empty(), TransmitFileOptions.UseDefaultWorkerThread)); } else { - await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path)); + ex = await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path)); } + Assert.Equal(SocketError.NotConnected, ex.SocketErrorCode); } public static IEnumerable SendFile_MemberData() From 8ad1631c71057ac085268f80ae28ab26c54dfff2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 19:18:52 +0100 Subject: [PATCH 09/12] SliceBuffers_Success --- .../tests/FunctionalTests/SendFile.cs | 27 +++++++++++++++++++ .../tests/FunctionalTests/SocketTestHelper.cs | 1 + 2 files changed, 28 insertions(+) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index 4e3dbe78fe2db..c21b1cb7cee9e 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -196,6 +196,33 @@ public async Task NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) Assert.Equal(0, client.Available); } + [Fact] + public async Task SliceBuffers_Success() + { + if (!SupportsSendFileSlicing) return; // The overloads under test only support sending byte[] + + Random rnd = new Random(0); + + ArraySegment preBuffer = new ArraySegment(new byte[100], 25, 50); + ArraySegment postBuffer = new ArraySegment(new byte[100], 25, 50); + rnd.NextBytes(preBuffer); + rnd.NextBytes(postBuffer); + + byte[] expected = preBuffer.ToArray().Concat(postBuffer.ToArray()).ToArray(); + + (Socket client, Socket server) = SocketTestExtensions.CreateConnectedSocketPair(); + + using (client) + using (server) + { + await SendFileAsync(client, null, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); + byte[] receiveBuffer = new byte[100]; + int receivedBytes = server.Receive(receiveBuffer); + Assert.Equal(100, receivedBytes); + AssertExtensions.SequenceEqual(expected, receiveBuffer); + } + } + [ActiveIssue("https://github.com/dotnet/runtime/issues/42534", TestPlatforms.Windows)] [OuterLoop("Creates and sends a file several gigabytes long")] [Fact] diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs index 3e6740111b0ca..3eb83b0bb3ff3 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SocketTestHelper.cs @@ -426,6 +426,7 @@ public Task SendFileAsync(Socket s, string fileName, ArraySegment preBuffe public bool SupportsMultiConnect => _socketHelper.SupportsMultiConnect; public bool SupportsAcceptIntoExistingSocket => _socketHelper.SupportsAcceptIntoExistingSocket; public bool SupportsAcceptReceive => _socketHelper.SupportsAcceptReceive; + public bool SupportsSendFileSlicing => _socketHelper.SupportsSendFileSlicing; public void Listen(Socket s, int backlog) => _socketHelper.Listen(s, backlog); public void ConfigureNonBlocking(Socket s) => _socketHelper.ConfigureNonBlocking(s); } From 197c90fac6fab4d1a67bcbdd5845488f23292629 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 26 Jan 2021 19:23:09 +0100 Subject: [PATCH 10/12] better comment --- .../System.Net.Sockets/tests/FunctionalTests/SendFile.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index c21b1cb7cee9e..15faf1ef7fa17 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -199,7 +199,7 @@ public async Task NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) [Fact] public async Task SliceBuffers_Success() { - if (!SupportsSendFileSlicing) return; // The overloads under test only support sending byte[] + if (!SupportsSendFileSlicing) return; // The overloads under test only support sending byte[] without offset and length Random rnd = new Random(0); From 7f6b39ad59da7f52d5bfe234f7ce3e9c95f659cc Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 27 Jan 2021 11:47:39 +0100 Subject: [PATCH 11/12] SendFileBase -> SendFile --- .../tests/FunctionalTests/SendFile.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index 15faf1ef7fa17..892a671e0e17a 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -13,9 +13,9 @@ namespace System.Net.Sockets.Tests { - public abstract class SendFileBase : SocketTestHelperBase where T : SocketHelperBase, new() + public abstract class SendFile : SocketTestHelperBase where T : SocketHelperBase, new() { - protected SendFileBase(ITestOutputHelper output) : base(output) + protected SendFile(ITestOutputHelper output) : base(output) { } @@ -382,27 +382,27 @@ private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte } } - public sealed class SendFile_SyncSpan : SendFileBase + public sealed class SendFile_SyncSpan : SendFile { public SendFile_SyncSpan(ITestOutputHelper output) : base(output) { } } - public sealed class SendFile_SyncSpanForceNonBlocking : SendFileBase + public sealed class SendFile_SyncSpanForceNonBlocking : SendFile { public SendFile_SyncSpanForceNonBlocking(ITestOutputHelper output) : base(output) { } } - public sealed class SendFile_ArraySync : SendFileBase + public sealed class SendFile_ArraySync : SendFile { public SendFile_ArraySync(ITestOutputHelper output) : base(output) { } } - public sealed class SendFile_SyncForceNonBlocking : SendFileBase + public sealed class SendFile_SyncForceNonBlocking : SendFile { public SendFile_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } } - public sealed class SendFile_Apm : SendFileBase + public sealed class SendFile_Apm : SendFile { public SendFile_Apm(ITestOutputHelper output) : base(output) { } From 71d00c65bb5de21b97659eb65dd710ab2756bff2 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 27 Jan 2021 12:13:54 +0100 Subject: [PATCH 12/12] split out large case of IncludeFile_Success to OuterLoop --- .../System.Net.Sockets/tests/FunctionalTests/SendFile.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index 892a671e0e17a..5cb496f253bf2 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -96,7 +96,7 @@ public static IEnumerable SendFile_MemberData() { foreach (bool sendPreAndPostBuffers in new[] { true, false }) { - foreach (int bytesToSend in new[] { 512, 1024, 12345678 }) + foreach (int bytesToSend in new[] { 512, 1024 }) { yield return new object[] { listenAt, sendPreAndPostBuffers, bytesToSend }; } @@ -104,6 +104,11 @@ public static IEnumerable SendFile_MemberData() } } + [OuterLoop("Creates a file of ~12MB, execution takes long.")] + [Theory] + [MemberData(nameof(Loopbacks))] + public Task IncludeFile_Success_LargeFile(IPAddress listenAt) => IncludeFile_Success(listenAt, true, 12_345_678); + [Theory] [MemberData(nameof(SendFile_MemberData))] public async Task IncludeFile_Success(IPAddress listenAt, bool sendPreAndPostBuffers, int bytesToSend)