Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 25 additions & 2 deletions src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1356,7 +1356,7 @@ public int SendTo(byte[] buffer, int offset, int size, SocketFlags socketFlags,
ThrowIfDisposed();

ValidateBufferArguments(buffer, offset, size);
ArgumentNullException.ThrowIfNull(remoteEP);
ValidateSendToEndpointAndState(remoteEP, nameof(remoteEP));

ValidateBlockingMode();
if (NetEventSource.Log.IsEnabled()) NetEventSource.Info(this, $"SRC:{LocalEndPoint} size:{size} remoteEP:{remoteEP}");
Expand Down Expand Up @@ -1439,7 +1439,7 @@ public int SendTo(ReadOnlySpan<byte> buffer, SocketFlags socketFlags, EndPoint r
if (!Socket.OSSupportsThreads) throw new PlatformNotSupportedException(); // TODO remove with https://github.com/dotnet/runtime/pull/107185

ThrowIfDisposed();
ArgumentNullException.ThrowIfNull(remoteEP);
ValidateSendToEndpointAndState(remoteEP, nameof(remoteEP));

ValidateBlockingMode();

Expand Down Expand Up @@ -3280,6 +3280,11 @@ private bool SendToAsync(SocketAsyncEventArgs e, CancellationToken cancellationT
throw new ArgumentException(SR.Format(SR.InvalidNullArgument, "e.RemoteEndPoint"), nameof(e));
}

if (endPointSnapshot is not null && !CanTryAddressFamily(endPointSnapshot.AddressFamily))
{
throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, endPointSnapshot.AddressFamily, _addressFamily), nameof(e));
}

if (e._socketAddress != null && endPointSnapshot is IPEndPoint ipep && e._socketAddress.Family == endPointSnapshot?.AddressFamily)
{
// we have matching SocketAddress. Since this is only used internally, it is ok to overwrite it without
Expand Down Expand Up @@ -3987,6 +3992,24 @@ private void ValidateReceiveFromEndpointAndState(EndPoint remoteEndPoint, string
}
}

// Validates that the remoteEndPoint is compatible with the Socket so that a SendTo call won't fail deep
// inside the OS PAL with a SocketError.InvalidArgument. This mirrors the address-family guard already
// applied to the ReceiveFrom/ReceiveMessageFrom methods so the SendTo family behaves consistently.
private void ValidateSendToEndpointAndState(EndPoint remoteEndPoint, string remoteEndPointArgumentName)
{
ArgumentNullException.ThrowIfNull(remoteEndPoint, remoteEndPointArgumentName);

if (remoteEndPoint is DnsEndPoint)
{
throw new ArgumentException(SR.Format(SR.net_sockets_invalid_dnsendpoint, remoteEndPointArgumentName), remoteEndPointArgumentName);
}

if (!CanTryAddressFamily(remoteEndPoint.AddressFamily))
{
throw new ArgumentException(SR.Format(SR.net_InvalidEndPointAddressFamily, remoteEndPoint.AddressFamily, _addressFamily), remoteEndPointArgumentName);
}
}

// ValidateBlockingMode - called before synchronous calls to validate
// the fact that we are in blocking mode (not in non-blocking mode) so the
// call will actually be synchronous.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -880,9 +880,11 @@ protected DualModeConnectionlessSendToBase(ITestOutputHelper output) : base(outp
[Fact]
public async Task Socket_SendToV4IPEndPointToV4Host_Throws()
{
// "The supplied EndPoint of AddressFamily InterNetwork is not valid for this Socket, use InterNetworkV6 instead."
// https://github.com/dotnet/runtime/issues/47772
using Socket socket = new Socket(SocketType.Dgram, ProtocolType.Udp);
socket.DualMode = false;
await Assert.ThrowsAsync<SocketException>(
await Assert.ThrowsAsync<ArgumentException>(
() => SendToAsync(socket, new byte[1], new IPEndPoint(IPAddress.Loopback, DualModeBase.UnusedPort)));
}

Expand Down
15 changes: 15 additions & 0 deletions src/libraries/System.Net.Sockets/tests/FunctionalTests/SendTo.cs
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,21 @@ public async Task NullSocketAddress_Throws_ArgumentException()
await AssertThrowsSynchronously<ArgumentNullException>(() => socket.SendToAsync(new byte[1], SocketFlags.None, socketAddress).AsTask());
}

// https://github.com/dotnet/runtime/issues/47772
// SendTo should validate the remote end point's address family up front (like ReceiveFrom does)
// instead of failing deep inside the OS PAL with a SocketError.InvalidArgument.
[Fact]
public async Task AddressFamilyDoesNotMatch_Throws_ArgumentException()
{
using var ipv4Socket = CreateSocket();
EndPoint ipV6Endpoint = GetGetDummyTestEndpoint(AddressFamily.InterNetworkV6);
await AssertThrowsSynchronously<ArgumentException>(() => SendToAsync(ipv4Socket, new ArraySegment<byte>(new byte[1]), ipV6Endpoint));

// The synchronous byte[] and span overloads must behave consistently as well.
Assert.Throws<ArgumentException>(() => ipv4Socket.SendTo(new byte[1], ipV6Endpoint));
Assert.Throws<ArgumentException>(() => ipv4Socket.SendTo(new byte[1].AsSpan(), SocketFlags.None, ipV6Endpoint));
}

[Fact]
public async Task Datagram_UDP_ShouldImplicitlyBindLocalEndpoint()
{
Expand Down
Loading