private void InnerStartOperationReceiveMessageFrom()
{
// WSARecvMsg uses a WSAMsg descriptor.
// The WSAMsg buffer is pinned with a GCHandle to avoid complicating the use of Overlapped.
// WSAMsg contains a pointer to a sockaddr.
// The sockaddr is pinned with a GCHandle to avoid complicating the use of Overlapped.
// WSAMsg contains a pointer to a WSABuffer array describing data buffers.
// WSAMsg also contains a single WSABuffer describing a control buffer.
PinSocketAddressBuffer();
// Create and pin a WSAMessageBuffer if none already.
if (_wsaMessageBuffer == null)
{
_wsaMessageBuffer = new byte[s_wsaMsgSize];
_wsaMessageBufferGCHandle = GCHandle.Alloc(_wsaMessageBuffer, GCHandleType.Pinned);
_ptrWSAMessageBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(_wsaMessageBuffer, 0);
}
// Create and pin an appropriately sized control buffer if none already
IPAddress ipAddress = (_socketAddress.Family == AddressFamily.InterNetworkV6 ? _socketAddress.GetIPAddress() : null);
bool ipv4 = (_currentSocket.AddressFamily == AddressFamily.InterNetwork || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode
bool ipv6 = _currentSocket.AddressFamily == AddressFamily.InterNetworkV6;
if (ipv4 && (_controlBuffer == null || _controlBuffer.Length != s_controlDataSize))
{
if (_controlBufferGCHandle.IsAllocated)
{
_controlBufferGCHandle.Free();
}
_controlBuffer = new byte[s_controlDataSize];
}
else if (ipv6 && (_controlBuffer == null || _controlBuffer.Length != s_controlDataIPv6Size))
{
if (_controlBufferGCHandle.IsAllocated)
{
_controlBufferGCHandle.Free();
}
_controlBuffer = new byte[s_controlDataIPv6Size];
}
if (!_controlBufferGCHandle.IsAllocated)
{
_controlBufferGCHandle = GCHandle.Alloc(_controlBuffer, GCHandleType.Pinned);
_ptrControlBuffer = Marshal.UnsafeAddrOfPinnedArrayElement(_controlBuffer, 0);
}
// If single buffer we need a pinned 1 element WSABuffer.
if (_buffer != null)
{
if (_wsaRecvMsgWSABufferArray == null)
{
_wsaRecvMsgWSABufferArray = new WSABuffer[1];
}
_wsaRecvMsgWSABufferArray[0].Pointer = _ptrSingleBuffer;
_wsaRecvMsgWSABufferArray[0].Length = _count;
_wsaRecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(_wsaRecvMsgWSABufferArray, GCHandleType.Pinned);
_ptrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(_wsaRecvMsgWSABufferArray, 0);
}
else
{
// Just pin the multi-buffer WSABuffer.
_wsaRecvMsgWSABufferArrayGCHandle = GCHandle.Alloc(_wsaBufferArray, GCHandleType.Pinned);
_ptrWSARecvMsgWSABufferArray = Marshal.UnsafeAddrOfPinnedArrayElement(_wsaBufferArray, 0);
}
// Fill in WSAMessageBuffer.
unsafe
{
Interop.Winsock.WSAMsg* pMessage = (Interop.Winsock.WSAMsg*)_ptrWSAMessageBuffer; ;
pMessage->socketAddress = _ptrSocketAddressBuffer;
pMessage->addressLength = (uint)_socketAddress.Size;
pMessage->buffers = _ptrWSARecvMsgWSABufferArray;
if (_buffer != null)
{
pMessage->count = (uint)1;
}
else
{
pMessage->count = (uint)_wsaBufferArray.Length;
}
if (_controlBuffer != null)
{
pMessage->controlBuffer.Pointer = _ptrControlBuffer;
pMessage->controlBuffer.Length = _controlBuffer.Length;
}
pMessage->flags = _socketFlags;
}
}