private static unsafe int Receive(SafeCloseSocket socket, SocketFlags flags, IList<ArraySegment<byte>> buffers, byte[] socketAddress, ref int socketAddressLen, out SocketFlags receivedFlags, out Interop.Error errno)
{
int available;
errno = Interop.Sys.GetBytesAvailable(socket, &available);
if (errno != Interop.Error.SUCCESS)
{
receivedFlags = 0;
return -1;
}
if (available == 0)
{
// Always request at least one byte.
available = 1;
}
// Pin buffers and set up iovecs.
int maxBuffers = buffers.Count;
var handles = new GCHandle[maxBuffers];
var iovecs = new Interop.Sys.IOVector[maxBuffers];
int sockAddrLen = 0;
if (socketAddress != null)
{
sockAddrLen = socketAddressLen;
}
long received = 0;
int toReceive = 0, iovCount = maxBuffers;
try
{
for (int i = 0; i < maxBuffers; i++)
{
ArraySegment<byte> buffer = buffers[i];
handles[i] = GCHandle.Alloc(buffer.Array, GCHandleType.Pinned);
iovecs[i].Base = &((byte*)handles[i].AddrOfPinnedObject())[buffer.Offset];
int space = buffer.Count;
toReceive += space;
if (toReceive >= available)
{
iovecs[i].Count = (UIntPtr)(space - (toReceive - available));
toReceive = available;
iovCount = i + 1;
break;
}
iovecs[i].Count = (UIntPtr)space;
}
// 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
};
errno = Interop.Sys.ReceiveMessage(socket, &messageHeader, flags, &received);
receivedFlags = messageHeader.Flags;
sockAddrLen = messageHeader.SocketAddressLen;
}
}
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;
}
socketAddressLen = sockAddrLen;
return checked((int)received);
}