Skip to content

Commit

Permalink
support InfiniteTimeSpan in Select (#73204)
Browse files Browse the repository at this point in the history
* support InfiniteTimeSpan in Select

* fix test

* feedback from review

* Apply suggestions from code review

Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com>

Co-authored-by: Marie Píchová <11718369+ManickaP@users.noreply.github.com>
  • Loading branch information
wfurt and ManickaP committed Aug 12, 2022
1 parent 4f1c56f commit afc9675
Show file tree
Hide file tree
Showing 2 changed files with 67 additions and 5 deletions.
20 changes: 15 additions & 5 deletions src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2155,7 +2155,7 @@ public bool Poll(int microSeconds, SelectMode mode)
}

/// <summary>Determines the status of the <see cref="Socket"/>.</summary>
/// <param name="timeout">The time to wait for a response.</param>
/// <param name="timeout">The time to wait for a response. <see cref="Timeout.InfiniteTimeSpan"/> indicates an infinite timeout.</param>
/// <param name="mode">One of the <see cref="SelectMode"/> values.</param>
/// <returns>
/// The status of the <see cref="Socket"/> based on the polling mode value passed in the <paramref name="mode"/> parameter.
Expand All @@ -2167,7 +2167,7 @@ public bool Poll(int microSeconds, SelectMode mode)
/// does not block and the connection has failed, or if OutOfBandInline is not set and out-of-band data is available.
/// Otherwise, it returns <see langword="false"/>.
/// </returns>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="timeout"/> is less than -1 milliseconds or greater than <see cref="int.MaxValue"/> milliseconds.</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="timeout"/> was negative or greater than TimeSpan.FromMicroseconds(int.MaxValue).</exception>
/// <exception cref="SocketException">An error occurred when attempting to access the socket.</exception>
/// <exception cref="ObjectDisposedException">The <see cref="Socket"/> has been closed.</exception>
public bool Poll(TimeSpan timeout, SelectMode mode) =>
Expand Down Expand Up @@ -2217,19 +2217,29 @@ public static void Select(IList? checkRead, IList? checkWrite, IList? checkError
/// <param name="checkRead">An <see cref="IList"/> of <see cref="Socket"/> instances to check for readability.</param>
/// <param name="checkWrite">An <see cref="IList"/> of <see cref="Socket"/> instances to check for writability.</param>
/// <param name="checkError">An <see cref="IList"/> of <see cref="Socket"/> instances to check for errors.</param>
/// <param name="timeout">The timeout value. A value equal to -1 microseconds indicates an infinite timeout.</param>
/// <param name="timeout">The timeout value. A value equal to <see cref="Timeout.InfiniteTimeSpan"/> indicates an infinite timeout.</param>
/// <exception cref="ArgumentNullException">The <paramref name="checkRead"/>, <paramref name="checkWrite"/>, or <paramref name="checkError"/> parameter is <see langword="null"/> or empty.</exception>
/// <exception cref="ArgumentOutOfRangeException">The <paramref name="checkRead"/>, <paramref name="checkWrite"/>, or <paramref name="checkError"/> parameter contains too many sockets.</exception>
/// <exception cref="ArgumentOutOfRangeException">The <paramref name="timeout"/> was less than -1 microseconds or greater than <see cref="int.MaxValue"/> microseconds</exception>
/// <exception cref="ArgumentOutOfRangeException">The <paramref name="timeout"/> was negative or greater than TimeSpan.FromMicroseconds(int.MaxValue).</exception>
/// <exception cref="SocketException">An error occurred when attempting to access the socket.</exception>
/// <exception cref="ObjectDisposedException">One or more sockets was disposed.</exception>
public static void Select(IList? checkRead, IList? checkWrite, IList? checkError, TimeSpan timeout) =>
Select(checkRead, checkWrite, checkError, ToTimeoutMicroseconds(timeout));

private static int ToTimeoutMicroseconds(TimeSpan timeout)
{
if (timeout == Timeout.InfiniteTimeSpan)
{
return -1;
}

if (timeout < TimeSpan.Zero)
{
throw new ArgumentOutOfRangeException(nameof(timeout));
}
long totalMicroseconds = (long)timeout.TotalMicroseconds;
if (totalMicroseconds < -1 || totalMicroseconds > int.MaxValue)

if (totalMicroseconds > int.MaxValue)
{
throw new ArgumentOutOfRangeException(nameof(timeout));
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -371,6 +371,58 @@ public void Select_NullOrEmptyLists_Throws_ArgumentNull_TimeSpan()
Assert.Throws<ArgumentNullException>(() => Socket.Select(emptyList, emptyList, emptyList, nonInfinity));
}

[Fact]
public void SelectPoll_NegativeTimeSpan_Throws()
{
using (Socket host = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
host.Bind(new IPEndPoint(IPAddress.Loopback, 0));
host.Listen(1);
Task accept = host.AcceptAsync();

using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
s.Connect(new IPEndPoint(IPAddress.Loopback, ((IPEndPoint)host.LocalEndPoint).Port));

var list = new List<Socket>();
list.Add(s);

Assert.Throws<ArgumentOutOfRangeException>(() => Socket.Select(null, list, null, TimeSpan.FromMicroseconds(-1)));
Assert.Throws<ArgumentOutOfRangeException>(() => Socket.Select(null, list, null, TimeSpan.FromMicroseconds((double)int.MaxValue + 1)));
Assert.Throws<ArgumentOutOfRangeException>(() => Socket.Select(null, list, null, TimeSpan.FromMilliseconds(-1.1)));

Assert.Throws<ArgumentOutOfRangeException>(() => s.Poll(TimeSpan.FromMicroseconds(-1), SelectMode.SelectWrite));
Assert.Throws<ArgumentOutOfRangeException>(() => s.Poll(TimeSpan.FromMicroseconds((double)int.MaxValue + 1), SelectMode.SelectWrite));
Assert.Throws<ArgumentOutOfRangeException>(() => s.Poll(TimeSpan.FromMilliseconds(-1.1), SelectMode.SelectWrite));
}
}
}

[Fact]
public void SelectPoll_InfiniteTimeSpan_Ok()
{
using (Socket host = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
host.Bind(new IPEndPoint(IPAddress.Loopback, 0));
host.Listen(1);
Task accept = host.AcceptAsync();

using (Socket s = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
s.Connect(new IPEndPoint(IPAddress.Loopback, ((IPEndPoint)host.LocalEndPoint).Port));

var list = new List<Socket>();
list.Add(s);

// should be writable
Socket.Select(null, list, null, Timeout.InfiniteTimeSpan);
Socket.Select(null, list, null, -1);
s.Poll(Timeout.InfiniteTimeSpan, SelectMode.SelectWrite);
s.Poll(-1, SelectMode.SelectWrite);
}
}
}

[Fact]
public void Select_LargeList_Throws_ArgumentOutOfRange()
{
Expand Down

0 comments on commit afc9675

Please sign in to comment.