diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs index d138281212564..5cb496f253bf2 100644 --- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs +++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs @@ -8,118 +8,69 @@ using System.Threading.Tasks; using Xunit; +using Xunit.Abstractions; using Xunit.Sdk; namespace System.Net.Sockets.Tests { - public class SendFileTest : FileCleanupTestBase + public abstract class SendFile : SocketTestHelperBase where T : SocketHelperBase, new() { - public static IEnumerable SendFile_MemberData() + protected SendFile(ITestOutputHelper output) : base(output) { - 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() + [Fact] + public async Task Disposed_ThrowsException() { - foreach (object[] memberData in SendFile_MemberData()) - { - yield return memberData.Concat(new object[] { true }).ToArray(); - yield return memberData.Concat(new object[] { false }).ToArray(); - } + 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)); } - private string 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); - - string path = Path.GetTempFileName(); - File.WriteAllBytes(path, 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 path; - } [Fact] - public void Disposed_ThrowsException() + public async Task NotConnected_ThrowsNotSupportedException() { - 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); + + await Assert.ThrowsAsync(() => SendFileAsync(s, null)); + await Assert.ThrowsAsync(() => SendFileAsync(s, null, null, null, TransmitFileOptions.UseDefaultWorkerThread)); } - [Fact] - public void EndSendFile_NullAsyncResult_Throws() + [Theory] + [InlineData(false)] + [InlineData(true)] + public async Task FileDoesNotExist_ThrowsFileNotFoundException(bool useOverloadWithBuffers) { - using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) - { - Assert.Throws(() => s.EndSendFile(null)); - } - } + string doesNotExist = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); + (Socket client, Socket server) = SocketTestExtensions.CreateConnectedSocketPair(); - [Fact] - public void NotConnected_ThrowsException() - { - using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp)) + using (client) + using (server) { - 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)); + if (!useOverloadWithBuffers) + { + await Assert.ThrowsAsync(() => SendFileAsync(client, doesNotExist)); + } + else + { + await Assert.ThrowsAsync(() => SendFileAsync(client, doesNotExist, null, null, TransmitFileOptions.UseDefaultWorkerThread)); + } } } - [ConditionalTheory] - [PlatformSpecific(TestPlatforms.Windows)] - [InlineData(true)] + [Theory] [InlineData(false)] - public async Task UdpConnection_ThrowsException(bool useAsync) + [InlineData(true)] + [PlatformSpecific(TestPlatforms.Windows)] + public async Task UdpConnection_ThrowsException(bool usePreAndPostbufferOverload) { // Create file to send 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); @@ -127,68 +78,94 @@ public async Task UdpConnection_ThrowsException(bool useAsync) client.Connect(listener.LocalEndPoint); - if (useAsync) + SocketException ex; + if (usePreAndPostbufferOverload) { - await Assert.ThrowsAsync(() => Task.Factory.FromAsync(client.BeginSendFile, client.EndSendFile, filename, null)); + ex = await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path, Array.Empty(), Array.Empty(), TransmitFileOptions.UseDefaultWorkerThread)); } else { - Assert.Throws(() => client.SendFile(filename)); + ex = await Assert.ThrowsAsync(() => SendFileAsync(client, tempFile.Path)); } + Assert.Equal(SocketError.NotConnected, ex.SocketErrorCode); + } - // Clean up the file we created - File.Delete(filename); + 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 }) + { + yield return new object[] { listenAt, sendPreAndPostBuffers, bytesToSend }; + } + } + } } + [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] - [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) + [MemberData(nameof(SendFile_MemberData))] + public async Task IncludeFile_Success(IPAddress listenAt, bool sendPreAndPostBuffers, int bytesToSend) { - 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); + const int ListenBacklog = 1; + const int TestTimeout = 30000; - client.Connect(listener.LocalEndPoint); - using Socket server = listener.Accept(); + // Create file to send + byte[] preBuffer; + byte[] postBuffer; + Fletcher32 sentChecksum; + using TempFile tempFile = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); - if (useAsync) - { - await Task.Factory.FromAsync(server.BeginSendFile, server.EndSendFile, null, null); - } - else + // 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(() => { - server.SendFile(null); - } - Assert.Equal(0, client.Available); + using (server) + { + Socket remote = server.Accept(); + Assert.NotNull(remote); - byte[] preBuffer = usePreBuffer ? new byte[1] : null; - byte[] postBuffer = usePostBuffer ? new byte[1] : null; - int bytesExpected = (usePreBuffer ? 1 : 0) + (usePostBuffer ? 1 : 0); + using (remote) + { + var recvBuffer = new byte[256]; + while (true) + { + int received = remote.Receive(recvBuffer, 0, recvBuffer.Length, SocketFlags.None); + if (received == 0) + { + break; + } - 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); - } + bytesReceived += received; + receivedChecksum.Add(recvBuffer, 0, received); + } + } + } + }); - byte[] receiveBuffer = new byte[1]; - for (int i = 0; i < bytesExpected; i++) + // Run client + EndPoint serverEndpoint = server.LocalEndPoint; + using (var client = new Socket(serverEndpoint.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) { - Assert.Equal(1, client.Receive(receiveBuffer)); + await ConnectAsync(client, serverEndpoint); // Configures NonBlocking behavior + await SendFileAsync(client, tempFile.Path, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); + client.Shutdown(SocketShutdown.Send); } - Assert.Equal(0, client.Available); + await serverTask.TimeoutAfter(TestTimeout); + Assert.Equal(bytesToSend, bytesReceived); + Assert.Equal(sentChecksum.Sum, receivedChecksum.Sum); } [Theory] @@ -196,7 +173,7 @@ public async Task SendFile_NoFile_Succeeds(bool useAsync, bool usePreBuffer, boo [InlineData(false, true)] [InlineData(true, false)] [InlineData(true, true)] - public void SendFileSpan_NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) + 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); @@ -206,14 +183,14 @@ public void SendFileSpan_NoFile_Succeeds(bool usePreBuffer, bool usePostBuffer) client.Connect(listener.LocalEndPoint); using Socket server = listener.Accept(); - 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); - server.SendFile(null, preBuffer.AsSpan(), postBuffer.AsSpan(), TransmitFileOptions.UseDefaultWorkerThread); + await SendFileAsync(server, null, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread); byte[] receiveBuffer = new byte[1]; for (int i = 0; i < bytesExpected; i++) @@ -224,17 +201,42 @@ public void SendFileSpan_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[] without offset and length + + 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")] - [Theory] - [InlineData(false)] - [InlineData(true)] - public async Task SendFile_GreaterThan2GBFile_SendsAllBytes(bool useAsync) + [Fact] + public async Task GreaterThan2GBFile_SendsAllBytes() { 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); } @@ -249,17 +251,7 @@ public async Task SendFile_GreaterThan2GBFile_SendsAllBytes(bool useAsync) await new Task[] { - Task.Run(async () => - { - if (useAsync) - { - await Task.Factory.FromAsync(server.BeginSendFile, server.EndSendFile, tmpFile, null); - } - else - { - server.SendFile(tmpFile); - } - }), + SendFileAsync(server, tmpFile.Path), Task.Run(() => { byte[] buffer = new byte[100_000]; @@ -275,83 +267,8 @@ public async Task SendFile_GreaterThan2GBFile_SendsAllBytes(bool useAsync) }.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; - string filename = 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(filename, 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); - - // Clean up the file we created - File.Delete(filename); - } - [Fact] - public async Task SyncSendFileGetsCanceledByDispose() + 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 @@ -362,16 +279,16 @@ await RetryHelper.ExecuteAsync(async () => (Socket socket1, Socket socket2) = SocketTestExtensions.CreateConnectedSocketPair(); using (socket2) { - Task socketOperation = Task.Run(() => + Task socketOperation = Task.Run(async () => { // 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); + await SendFileAsync(socket1, tempFile.Path); }); // Wait a little so the operation is started. @@ -383,6 +300,7 @@ await RetryHelper.ExecuteAsync(async () => await disposeTask; SocketError? localSocketError = null; + bool thrownDisposed = false; try { await socketOperation; @@ -392,12 +310,23 @@ await RetryHelper.ExecuteAsync(async () => localSocketError = se.SocketErrorCode; } catch (ObjectDisposedException) - { } - Assert.Equal(SocketError.ConnectionAborted, localSocketError); + { + 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 (!PlatformDetection.IsOSXLike) + if (!(UsesSync && PlatformDetection.IsOSXLike)) { SocketError? peerSocketError = null; var receiveBuffer = new byte[4096]; @@ -423,63 +352,80 @@ 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) + private TempFile CreateFileToSend(int size, bool sendPreAndPostBuffers, out byte[] preBuffer, out byte[] postBuffer, out Fletcher32 checksum) { - const int ListenBacklog = 1, TestTimeout = 30000; - // Create file to send - byte[] preBuffer, postBuffer; - Fletcher32 sentChecksum; - string filename = CreateFileToSend(bytesToSend, sendPreAndPostBuffers, out preBuffer, out postBuffer, out sentChecksum); + var random = new Random(); + int fileSize = sendPreAndPostBuffers ? size - 512 : size; - // Start server - using (var listener = new Socket(listenAt.AddressFamily, SocketType.Stream, ProtocolType.Tcp)) + checksum = new Fletcher32(); + + preBuffer = null; + if (sendPreAndPostBuffers) { - listener.BindToAnonymousPort(listenAt); - listener.Listen(ListenBacklog); + preBuffer = new byte[256]; + random.NextBytes(preBuffer); + checksum.Add(preBuffer, 0, preBuffer.Length); + } - int bytesReceived = 0; - var receivedChecksum = new Fletcher32(); + byte[] fileBuffer = new byte[fileSize]; + random.NextBytes(fileBuffer); - 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(filename, preBuffer, postBuffer, TransmitFileOptions.UseDefaultWorkerThread, callback, state), - iar => client.EndSendFile(iar), - null); - client.Shutdown(SocketShutdown.Send); - } - }); + var tempFile = TempFile.Create(fileBuffer); - // Wait for the tasks to complete - await (new[] { serverTask, clientTask }).WhenAllOrAnyFailed(TestTimeout); + checksum.Add(fileBuffer, 0, fileBuffer.Length); - // Validate the results - Assert.Equal(bytesToSend, bytesReceived); - Assert.Equal(sentChecksum.Sum, receivedChecksum.Sum); + postBuffer = null; + if (sendPreAndPostBuffers) + { + postBuffer = new byte[256]; + random.NextBytes(postBuffer); + checksum.Add(postBuffer, 0, postBuffer.Length); } - // Clean up the file we created - File.Delete(filename); + return tempFile; + } + } + + public sealed class SendFile_SyncSpan : SendFile + { + public SendFile_SyncSpan(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_SyncSpanForceNonBlocking : SendFile + { + public SendFile_SyncSpanForceNonBlocking(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_ArraySync : SendFile + { + public SendFile_ArraySync(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_SyncForceNonBlocking : SendFile + { + public SendFile_SyncForceNonBlocking(ITestOutputHelper output) : base(output) { } + } + + public sealed class SendFile_Apm : SendFile + { + 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 2e3801f7a7f17..a401f50d27f03 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.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.EndSendFile, 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 @@ -255,6 +269,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, _cts.Token).AsTask() ; + 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 @@ -344,7 +360,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, @@ -399,6 +416,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; @@ -408,6 +428,7 @@ public Task ReceiveMessageFromAsync(Socket s, Ar 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); } @@ -419,7 +440,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 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 f79246b4d34ef..b0c0abb4a0337 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 @@ -99,6 +99,7 @@ +