diff --git a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj
index 054cc155bd13f7..283d47ee4feda7 100644
--- a/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj
+++ b/src/libraries/System.Net.Sockets/src/System.Net.Sockets.csproj
@@ -179,6 +179,8 @@
Link="Common\Interop\Windows\Kernel32\Interop.SetFileCompletionNotificationModes.cs" />
+
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs
index 1cbf2d63ddfa4f..9606204175cac8 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/SocketPal.Windows.cs
@@ -295,8 +295,69 @@ public static unsafe SocketError SendFile(SafeSocketHandle handle, SafeFileHandl
fixed (byte* prePinnedBuffer = preBuffer)
fixed (byte* postPinnedBuffer = postBuffer)
{
- bool success = TransmitFileHelper(handle, fileHandle, null, (IntPtr)prePinnedBuffer, preBuffer.Length, (IntPtr)postPinnedBuffer, postBuffer.Length, flags);
- return success ? SocketError.Success : GetLastSocketError();
+ // Get file length if we have a file
+ long fileLength = 0;
+ if (fileHandle is not null)
+ {
+ fileLength = RandomAccess.GetLength(fileHandle);
+ }
+
+ // If file length exceeds int.MaxValue, we need to partition the sends
+ if (fileLength > int.MaxValue)
+ {
+ // Separate behavior/performance flags from terminal flags
+ // Behavior flags (WriteBehind, UseSystemThread, UseKernelApc) apply to all operations
+ // Terminal flags (Disconnect, ReuseSocket) apply only to the final operation
+ TransmitFileOptions behaviorFlags = flags & ~(TransmitFileOptions.Disconnect | TransmitFileOptions.ReuseSocket);
+
+ // Send preBuffer if present
+ if (preBuffer.Length > 0)
+ {
+ bool success = TransmitFileHelper(handle, null, null, (IntPtr)prePinnedBuffer, preBuffer.Length, IntPtr.Zero, 0, behaviorFlags);
+ if (!success)
+ {
+ return GetLastSocketError();
+ }
+ }
+
+ // Send file in chunks of int.MaxValue bytes
+ long offset = 0;
+ long remaining = fileLength;
+ while (remaining > 0)
+ {
+ int chunkSize = (int)Math.Min(remaining, int.MaxValue);
+
+ // Set the file pointer to the current offset
+ if (!Interop.Kernel32.SetFilePointerEx(fileHandle!, offset, out _, 0 /* FILE_BEGIN */))
+ {
+ return GetLastSocketError();
+ }
+
+ bool success = TransmitFileHelper(handle, fileHandle, null, IntPtr.Zero, 0, IntPtr.Zero, 0, behaviorFlags, chunkSize);
+ if (!success)
+ {
+ return GetLastSocketError();
+ }
+
+ offset += chunkSize;
+ remaining -= chunkSize;
+ }
+
+ // Send postBuffer with all flags (behavior + terminal flags apply to last operation)
+ bool finalSuccess = TransmitFileHelper(handle, null, null, IntPtr.Zero, 0, (IntPtr)postPinnedBuffer, postBuffer.Length, flags);
+ if (!finalSuccess)
+ {
+ return GetLastSocketError();
+ }
+
+ return SocketError.Success;
+ }
+ else
+ {
+ // File is small enough, use single call
+ bool success = TransmitFileHelper(handle, fileHandle, null, (IntPtr)prePinnedBuffer, preBuffer.Length, (IntPtr)postPinnedBuffer, postBuffer.Length, flags);
+ return success ? SocketError.Success : GetLastSocketError();
+ }
}
}
@@ -1004,7 +1065,8 @@ private static unsafe bool TransmitFileHelper(
int preBufferLength,
IntPtr pinnedPostBuffer,
int postBufferLength,
- TransmitFileOptions flags)
+ TransmitFileOptions flags,
+ int numberOfBytesToWrite = 0)
{
bool needTransmitFileBuffers = false;
Interop.Mswsock.TransmitFileBuffers transmitFileBuffers = default;
@@ -1027,14 +1089,14 @@ private static unsafe bool TransmitFileHelper(
IntPtr fileHandlePtr = IntPtr.Zero;
try
{
- if (fileHandle != null)
+ if (fileHandle is not null)
{
fileHandle.DangerousAddRef(ref releaseRef);
fileHandlePtr = fileHandle.DangerousGetHandle();
}
return Interop.Mswsock.TransmitFile(
- socket, fileHandlePtr, 0, 0, overlapped,
+ socket, fileHandlePtr, numberOfBytesToWrite, 0, overlapped,
needTransmitFileBuffers ? &transmitFileBuffers : null, flags);
}
finally
diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs
index 10313336876ce4..f85d68d05c8b13 100644
--- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs
+++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/SendFile.cs
@@ -484,7 +484,6 @@ protected SendFile_NonParallel(ITestOutputHelper output) : base(output)
{
}
- [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()