internal void SetUnmanagedStructures(IList <ArraySegment <byte> > buffers) { // Fill in Buffer Array structure that will be used for our send/recv Buffer. // Make sure we don't let the app mess up the buffer array enough to cause // corruption. int count = buffers.Count; ArraySegment <byte>[] buffersCopy = new ArraySegment <byte> [count]; for (int i = 0; i < count; i++) { buffersCopy[i] = buffers[i]; RangeValidationHelpers.ValidateSegment(buffersCopy[i]); } _wsaBuffers = new WSABuffer[count]; object[] objectsToPin = new object[count]; for (int i = 0; i < count; i++) { objectsToPin[i] = buffersCopy[i].Array; } base.SetUnmanagedStructures(objectsToPin); for (int i = 0; i < count; i++) { _wsaBuffers[i].Length = buffersCopy[i].Count; _wsaBuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffersCopy[i].Array, buffersCopy[i].Offset); } }
public static SocketError Receive(SafeCloseSocket handle, IList <ArraySegment <byte> > buffers, ref SocketFlags socketFlags, out int bytesTransferred) { int count = buffers.Count; WSABuffer[] WSABuffers = new WSABuffer[count]; GCHandle[] objectsToPin = null; try { objectsToPin = new GCHandle[count]; for (int i = 0; i < count; ++i) { ArraySegment <byte> buffer = buffers[i]; RangeValidationHelpers.ValidateSegment(buffer); objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); WSABuffers[i].Length = buffer.Count; WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array, buffer.Offset); } // This can throw ObjectDisposedException. unsafe { SocketError errorCode = Interop.Winsock.WSARecv( handle.DangerousGetHandle(), WSABuffers, count, out bytesTransferred, ref socketFlags, null, IntPtr.Zero); if (errorCode == SocketError.SocketError) { errorCode = GetLastSocketError(); } return(errorCode); } } finally { if (objectsToPin != null) { for (int i = 0; i < objectsToPin.Length; ++i) { if (objectsToPin[i].IsAllocated) { objectsToPin[i].Free(); } } } } }
public static SocketError Receive(SafeSocketHandle handle, IList <ArraySegment <byte> > buffers, SocketFlags socketFlags, out int bytesTransferred) { const int StackThreshold = 16; // arbitrary limit to avoid too much space on stack (note: may be over-sized, that's OK - length passed separately) int count = buffers.Count; bool useStack = count <= StackThreshold; WSABuffer[]? leasedWSA = null; GCHandle[]? leasedGC = null; Span <WSABuffer> WSABuffers = stackalloc WSABuffer[0]; Span <GCHandle> objectsToPin = stackalloc GCHandle[0]; if (useStack) { WSABuffers = stackalloc WSABuffer[StackThreshold]; objectsToPin = stackalloc GCHandle[StackThreshold]; } else { WSABuffers = leasedWSA = ArrayPool <WSABuffer> .Shared.Rent(count); objectsToPin = leasedGC = ArrayPool <GCHandle> .Shared.Rent(count); } objectsToPin = objectsToPin.Slice(0, count); objectsToPin.Clear(); // note: touched in finally try { for (int i = 0; i < count; ++i) { ArraySegment <byte> buffer = buffers[i]; RangeValidationHelpers.ValidateSegment(buffer); objectsToPin[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned); WSABuffers[i].Length = buffer.Count; WSABuffers[i].Pointer = Marshal.UnsafeAddrOfPinnedArrayElement(buffer.Array !, buffer.Offset); } unsafe { SocketError errorCode = Interop.Winsock.WSARecv( handle, WSABuffers, count, out bytesTransferred, ref socketFlags, null, IntPtr.Zero); if (errorCode == SocketError.SocketError) { errorCode = GetLastSocketError(); } return(errorCode); } } finally { for (int i = 0; i < count; ++i) { if (objectsToPin[i].IsAllocated) { objectsToPin[i].Free(); } } if (!useStack) { ArrayPool <WSABuffer> .Shared.Return(leasedWSA !); ArrayPool <GCHandle> .Shared.Return(leasedGC !); } } }