private static unsafe int Send(SafeCloseSocket socket, SocketFlags flags, IList<ArraySegment<byte>> buffers, ref int bufferIndex, ref int offset, byte[] socketAddress, int socketAddressLen, out Interop.Error errno)
{
// Pin buffers and set up iovecs.
int startIndex = bufferIndex, startOffset = offset;
int sockAddrLen = 0;
if (socketAddress != null)
{
sockAddrLen = socketAddressLen;
}
int maxBuffers = buffers.Count - startIndex;
var handles = new GCHandle[maxBuffers];
var iovecs = new Interop.Sys.IOVector[maxBuffers];
int sent;
int toSend = 0, iovCount = maxBuffers;
try
{
for (int i = 0; i < maxBuffers; i++, startOffset = 0)
{
ArraySegment<byte> buffer = buffers[startIndex + i];
Debug.Assert(buffer.Offset + startOffset < buffer.Array.Length, $"Unexpected values: Offset={buffer.Offset}, startOffset={startOffset}, Length={buffer.Array.Length}");
handles[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
iovecs[i].Base = &((byte*)handles[i].AddrOfPinnedObject())[buffer.Offset + startOffset];
toSend += (buffer.Count - startOffset);
iovecs[i].Count = (UIntPtr)(buffer.Count - startOffset);
}
// Make the call
fixed (byte* sockAddr = socketAddress)
fixed (Interop.Sys.IOVector* iov = iovecs)
{
var messageHeader = new Interop.Sys.MessageHeader {
SocketAddress = sockAddr,
SocketAddressLen = sockAddrLen,
IOVectors = iov,
IOVectorCount = iovCount
};
long bytesSent;
errno = Interop.Sys.SendMessage(socket, &messageHeader, flags, &bytesSent);
sent = checked((int)bytesSent);
}
}
finally
{
// Free GC handles.
for (int i = 0; i < iovCount; i++)
{
if (handles[i].IsAllocated)
{
handles[i].Free();
}
}
}
if (errno != Interop.Error.SUCCESS)
{
return -1;
}
// Update position.
int endIndex = bufferIndex, endOffset = offset, unconsumed = sent;
for (; endIndex < buffers.Count && unconsumed > 0; endIndex++, endOffset = 0)
{
int space = buffers[endIndex].Count - endOffset;
if (space > unconsumed)
{
endOffset += unconsumed;
break;
}
unconsumed -= space;
}
bufferIndex = endIndex;
offset = endOffset;
return sent;
}