bool ipv4 = (_currentSocket!.AddressFamily == AddressFamily.InterNetwork || (ipAddress != null && ipAddress.IsIPv4MappedToIPv6)); // DualMode
bool ipv6 = _currentSocket.AddressFamily == AddressFamily.InterNetworkV6;
- if (ipv4 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlData)))
+ if (ipv6 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlDataIPv6)))
{
- _controlBufferPinned = GC.AllocateUninitializedArray<byte>(sizeof(Interop.Winsock.ControlData), pinned: true);
+ _controlBufferPinned = GC.AllocateUninitializedArray<byte>(sizeof(Interop.Winsock.ControlDataIPv6), pinned: true);
}
- else if (ipv6 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlDataIPv6)))
+ else if (ipv4 && (_controlBufferPinned == null || _controlBufferPinned.Length != sizeof(Interop.Winsock.ControlData)))
{
- _controlBufferPinned = GC.AllocateUninitializedArray<byte>(sizeof(Interop.Winsock.ControlDataIPv6), pinned: true);
+ _controlBufferPinned = GC.AllocateUninitializedArray<byte>(sizeof(Interop.Winsock.ControlData), pinned: true);
}
// If single buffer we need a single element WSABuffer.
public static unsafe IPPacketInformation GetIPPacketInformation(Interop.Winsock.ControlDataIPv6* controlBuffer)
{
+ if (controlBuffer->length == (UIntPtr)sizeof(Interop.Winsock.ControlData))
+ {
+ // IPv4 client connectiong to dual mode socket.
+ return GetIPPacketInformation((Interop.Winsock.ControlData*)controlBuffer);
+ }
+
IPAddress address = controlBuffer->length != UIntPtr.Zero ?
new IPAddress(new ReadOnlySpan<byte>(controlBuffer->address, Interop.Winsock.IPv6AddressLength)) :
IPAddress.IPv6None;
bytesTransferred = 0;
receiveAddress = socketAddress;
ipPacketInformation = default(IPPacketInformation);
-
fixed (byte* ptrBuffer = buffer)
fixed (byte* ptrSocketAddress = socketAddress.Buffer)
{
ReceiveMessageFrom_Helper(IPAddress.IPv6Any, IPAddress.Loopback);
}
+ [Theory]
+ [InlineData(true)]
+ [InlineData(false)]
+ [PlatformSpecific(~TestPlatforms.OSX)] // ReceiveMessageFrom not supported on OSX
+ public void ReceiveMessageFromAsync_SocketAsyncEventArgs_Success(bool ipv4)
+ {
+ const int DataLength = 10;
+ AddressFamily family = ipv4 ? AddressFamily.InterNetwork : AddressFamily.InterNetworkV6;
+ IPAddress loopback = ipv4 ? IPAddress.Loopback : IPAddress.Loopback.MapToIPv6();
+ IPAddress clientAddress = ipv4 ? IPAddress.Loopback : IPAddress.IPv6Loopback;
+
+ var completed = new ManualResetEventSlim(false);
+ using (var sender = new Socket(family, SocketType.Dgram, ProtocolType.Udp))
+ using (var receiver = new Socket(AddressFamily.InterNetworkV6, SocketType.Dgram, ProtocolType.Udp))
+ {
+ receiver.DualMode = true;
+ receiver.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.PacketInformation, true);
+ receiver.SetSocketOption(SocketOptionLevel.IPv6, SocketOptionName.PacketInformation, true);
+ int receiverPort = receiver.BindToAnonymousPort(IPAddress.IPv6Any);
+
+ if (!ipv4)
+ {
+ sender.DualMode = true;
+ }
+
+ int senderPort = sender.BindToAnonymousPort(loopback);
+ var expectedEP = new IPEndPoint(IPAddress.Loopback.MapToIPv6(), senderPort);
+
+ var args = new SocketAsyncEventArgs() { RemoteEndPoint = new IPEndPoint(IPAddress.IPv6Any, 0) };
+ args.Completed += (s, e) => { Console.WriteLine("Got 1 packet {0} {1}", e.RemoteEndPoint, e.ReceiveMessageFromPacketInfo.Address); completed.Set(); };
+ args.SetBuffer(new byte[DataLength], 0, DataLength);
+
+ var ep = new IPEndPoint(loopback, receiverPort);
+ for (int iters = 0; iters < 5; iters++)
+ {
+ for (int i = 0; i < TestSettings.UDPRedundancy; i++)
+ {
+ sender.SendTo(new byte[DataLength], ep);
+ }
+
+ if (!receiver.ReceiveMessageFromAsync(args))
+ {
+ completed.Set();
+ }
+ Assert.True(completed.Wait(TestSettings.PassingTestTimeout), "Timeout while waiting for connection");
+ completed.Reset();
+
+ Assert.Equal(DataLength, args.BytesTransferred);
+ Assert.Equal(expectedEP, args.RemoteEndPoint);
+ Assert.True(args.ReceiveMessageFromPacketInfo.Address.Equals(IPAddress.Loopback) || args.ReceiveMessageFromPacketInfo.Address.Equals(IPAddress.Loopback.MapToIPv6()));
+ }
+ }
+ }
+
private void ReceiveMessageFrom_Helper(IPAddress listenOn, IPAddress connectTo, bool expectedToTimeout = false)
{
using (Socket serverSocket = new Socket(SocketType.Dgram, ProtocolType.Udp))