From 5f7db97fe9deb251b19f3d4079702d4ca1e037e1 Mon Sep 17 00:00:00 2001 From: Stephen Toub Date: Tue, 11 Feb 2020 11:29:32 -0800 Subject: [PATCH] Annotate System.Net.Ping for nullable reference types --- .../Interop/Windows/IpHlpApi/Interop.ICMP.cs | 3 +- .../NetworkInformation/UnixCommandLinePing.cs | 26 +++--- .../Common/src/System/Net/SocketAddress.cs | 5 +- .../System.Net.Ping/ref/System.Net.Ping.cs | 32 +++---- .../ref/System.Net.Ping.csproj | 1 + .../src/System.Net.Ping.csproj | 1 + .../Net/NetworkInformation/Ping.Unix.cs | 85 ++++++++++--------- .../Net/NetworkInformation/Ping.Windows.cs | 65 +++++++------- .../src/System/Net/NetworkInformation/Ping.cs | 48 +++++------ .../PingCompletedEventArgs.cs | 4 +- .../Net/NetworkInformation/PingException.cs | 4 +- .../Net/NetworkInformation/PingReply.cs | 28 +++--- 12 files changed, 156 insertions(+), 146 deletions(-) diff --git a/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs b/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs index 6705874d50200..220ac34a823fc 100644 --- a/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs +++ b/src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System; using System.Net.NetworkInformation; using System.Runtime.InteropServices; @@ -22,7 +23,7 @@ internal struct IPOptions internal byte optionsSize; internal IntPtr optionsData; - internal IPOptions(PingOptions options) + internal IPOptions(PingOptions? options) { ttl = 128; tos = 0; diff --git a/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs b/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs index 3a5c413679f8e..0944538eed898 100644 --- a/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs +++ b/src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Globalization; using System.IO; using System.Runtime.InteropServices; @@ -16,14 +17,14 @@ internal static class UnixCommandLinePing private const string s_ipv4PingFile = "ping"; private const string s_ipv6PingFile = "ping6"; - private static readonly string s_discoveredPing4UtilityPath = GetPingUtilityPath(ipv4: true); - private static readonly string s_discoveredPing6UtilityPath = GetPingUtilityPath(ipv4: false); + private static readonly string? s_discoveredPing4UtilityPath = GetPingUtilityPath(ipv4: true); + private static readonly string? s_discoveredPing6UtilityPath = GetPingUtilityPath(ipv4: false); private static readonly bool s_isBSD = RuntimeInformation.IsOSPlatform(OSPlatform.OSX) || RuntimeInformation.IsOSPlatform(OSPlatform.Create("FREEBSD")); private static readonly Lazy s_isBusybox = new Lazy(() => IsBusyboxPing(s_discoveredPing4UtilityPath)); // We don't want to pick up an arbitrary or malicious ping // command, so that's why we do the path probing ourselves. - private static string GetPingUtilityPath(bool ipv4) + private static string? GetPingUtilityPath(bool ipv4) { string fileName = ipv4 ? s_ipv4PingFile : s_ipv6PingFile; foreach (string folder in s_binFolders) @@ -39,14 +40,17 @@ private static string GetPingUtilityPath(bool ipv4) } // Check if found ping is symlink to busybox like alpine /bin/ping -> /bin/busybox - private static unsafe bool IsBusyboxPing(string pingBinary) + private static unsafe bool IsBusyboxPing(string? pingBinary) { - string linkedName = Interop.Sys.ReadLink(pingBinary); - - // If pingBinary is not link linkedName will be null - if (linkedName != null && linkedName.EndsWith("busybox", StringComparison.Ordinal)) + if (pingBinary != null) { - return true; + string? linkedName = Interop.Sys.ReadLink(pingBinary); + + // If pingBinary is not link linkedName will be null + if (linkedName != null && linkedName.EndsWith("busybox", StringComparison.Ordinal)) + { + return true; + } } return false; @@ -57,12 +61,12 @@ public enum PingFragmentOptions { Default, Do, Dont }; /// /// The location of the IPv4 ping utility on the current machine. /// - public static string Ping4UtilityPath { get { return s_discoveredPing4UtilityPath; } } + public static string? Ping4UtilityPath { get { return s_discoveredPing4UtilityPath; } } /// /// The location of the IPv6 ping utility on the current machine. /// - public static string Ping6UtilityPath { get { return s_discoveredPing6UtilityPath; } } + public static string? Ping6UtilityPath { get { return s_discoveredPing6UtilityPath; } } /// /// Constructs command line arguments appropriate for the ping or ping6 utility. diff --git a/src/libraries/Common/src/System/Net/SocketAddress.cs b/src/libraries/Common/src/System/Net/SocketAddress.cs index 310b8fc147cc4..a3a93bdb3bedb 100644 --- a/src/libraries/Common/src/System/Net/SocketAddress.cs +++ b/src/libraries/Common/src/System/Net/SocketAddress.cs @@ -2,6 +2,7 @@ // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. +#nullable enable using System.Diagnostics; using System.Globalization; using System.Net.Sockets; @@ -179,9 +180,9 @@ internal int GetAddressSizeOffset() return Buffer.Length - IntPtr.Size; } - public override bool Equals(object comparand) + public override bool Equals(object? comparand) { - SocketAddress castedComparand = comparand as SocketAddress; + SocketAddress? castedComparand = comparand as SocketAddress; if (castedComparand == null || this.Size != castedComparand.Size) { return false; diff --git a/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs b/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs index 08e1c48d870f7..847b3ec2c0a2b 100644 --- a/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs +++ b/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs @@ -37,34 +37,34 @@ public enum IPStatus public partial class Ping : System.ComponentModel.Component { public Ping() { } - public event System.Net.NetworkInformation.PingCompletedEventHandler PingCompleted { add { } remove { } } + public event System.Net.NetworkInformation.PingCompletedEventHandler? PingCompleted { add { } remove { } } protected override void Dispose(bool disposing) { } protected void OnPingCompleted(System.Net.NetworkInformation.PingCompletedEventArgs e) { } public System.Net.NetworkInformation.PingReply Send(System.Net.IPAddress address) { throw null; } public System.Net.NetworkInformation.PingReply Send(System.Net.IPAddress address, int timeout) { throw null; } public System.Net.NetworkInformation.PingReply Send(System.Net.IPAddress address, int timeout, byte[] buffer) { throw null; } - public System.Net.NetworkInformation.PingReply Send(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options) { throw null; } + public System.Net.NetworkInformation.PingReply Send(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; } public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress) { throw null; } public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, int timeout) { throw null; } public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer) { throw null; } - public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options) { throw null; } - public void SendAsync(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options, object userToken) { } - public void SendAsync(System.Net.IPAddress address, int timeout, byte[] buffer, object userToken) { } - public void SendAsync(System.Net.IPAddress address, int timeout, object userToken) { } - public void SendAsync(System.Net.IPAddress address, object userToken) { } - public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options, object userToken) { } - public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, object userToken) { } - public void SendAsync(string hostNameOrAddress, int timeout, object userToken) { } - public void SendAsync(string hostNameOrAddress, object userToken) { } + public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; } + public void SendAsync(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options, object? userToken) { } + public void SendAsync(System.Net.IPAddress address, int timeout, byte[] buffer, object? userToken) { } + public void SendAsync(System.Net.IPAddress address, int timeout, object? userToken) { } + public void SendAsync(System.Net.IPAddress address, object? userToken) { } + public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options, object? userToken) { } + public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, object? userToken) { } + public void SendAsync(string hostNameOrAddress, int timeout, object? userToken) { } + public void SendAsync(string hostNameOrAddress, object? userToken) { } public void SendAsyncCancel() { } public System.Threading.Tasks.Task SendPingAsync(System.Net.IPAddress address) { throw null; } public System.Threading.Tasks.Task SendPingAsync(System.Net.IPAddress address, int timeout) { throw null; } public System.Threading.Tasks.Task SendPingAsync(System.Net.IPAddress address, int timeout, byte[] buffer) { throw null; } - public System.Threading.Tasks.Task SendPingAsync(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options) { throw null; } + public System.Threading.Tasks.Task SendPingAsync(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; } public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress) { throw null; } public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, int timeout) { throw null; } public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer) { throw null; } - public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options) { throw null; } + public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; } } public partial class PingCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs { @@ -75,8 +75,8 @@ public partial class PingCompletedEventArgs : System.ComponentModel.AsyncComplet public partial class PingException : System.InvalidOperationException { protected PingException(System.Runtime.Serialization.SerializationInfo serializationInfo, System.Runtime.Serialization.StreamingContext streamingContext) { } - public PingException(string message) { } - public PingException(string message, System.Exception innerException) { } + public PingException(string? message) { } + public PingException(string? message, System.Exception? innerException) { } } public partial class PingOptions { @@ -90,7 +90,7 @@ public partial class PingReply internal PingReply() { } public System.Net.IPAddress Address { get { throw null; } } public byte[] Buffer { get { throw null; } } - public System.Net.NetworkInformation.PingOptions Options { get { throw null; } } + public System.Net.NetworkInformation.PingOptions? Options { get { throw null; } } public long RoundtripTime { get { throw null; } } public System.Net.NetworkInformation.IPStatus Status { get { throw null; } } } diff --git a/src/libraries/System.Net.Ping/ref/System.Net.Ping.csproj b/src/libraries/System.Net.Ping/ref/System.Net.Ping.csproj index 9d2579fdfeff5..b91f82444f42e 100644 --- a/src/libraries/System.Net.Ping/ref/System.Net.Ping.csproj +++ b/src/libraries/System.Net.Ping/ref/System.Net.Ping.csproj @@ -1,6 +1,7 @@ $(NetCoreAppCurrent) + enable diff --git a/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj b/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj index 92871b7712857..36d2f01f06dd8 100644 --- a/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj +++ b/src/libraries/System.Net.Ping/src/System.Net.Ping.csproj @@ -4,6 +4,7 @@ true $(NoWarn);CS1573 $(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix + enable diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs index 5b9fcb6b4ac70..b0b008d6d8b4b 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs @@ -4,6 +4,7 @@ using System.ComponentModel; using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.IO; using System.Net.Sockets; using System.Runtime.InteropServices; @@ -19,9 +20,9 @@ public partial class Ping private const int MinIpHeaderLengthInBytes = 20; private const int MaxIpHeaderLengthInBytes = 60; [ThreadStatic] - private static Random t_idGenerator; + private static Random? t_idGenerator; - private PingReply SendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private PingReply SendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { PingReply reply = RawSocketPermissions.CanUseRawSockets(address.AddressFamily) ? SendIcmpEchoRequestOverRawSocket(address, buffer, timeout, options) : @@ -29,7 +30,7 @@ private PingReply SendPingCore(IPAddress address, byte[] buffer, int timeout, Pi return reply; } - private async Task SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private async Task SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { Task t = RawSocketPermissions.CanUseRawSockets(address.AddressFamily) ? SendIcmpEchoRequestOverRawSocketAsync(address, buffer, timeout, options) : @@ -45,32 +46,23 @@ private async Task SendPingAsyncCore(IPAddress address, byte[] buffer return reply; } - private SocketConfig GetSocketConfig(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private SocketConfig GetSocketConfig(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { - SocketConfig config = new SocketConfig(); - config.EndPoint = new IPEndPoint(address, 0); - config.Timeout = timeout; - config.Options = options; - - config.IsIpv4 = address.AddressFamily == AddressFamily.InterNetwork; - config.ProtocolType = config.IsIpv4 ? ProtocolType.Icmp : ProtocolType.IcmpV6; - // Use a random value as the identifier. This doesn't need to be perfectly random // or very unpredictable, rather just good enough to avoid unexpected conflicts. - Random rand = t_idGenerator ?? (t_idGenerator = new Random()); - config.Identifier = (ushort)rand.Next((int)ushort.MaxValue + 1); + Random rand = t_idGenerator ??= new Random(); + ushort id = (ushort)rand.Next(ushort.MaxValue + 1); - IcmpHeader header = new IcmpHeader() - { - Type = config.IsIpv4 ? (byte)IcmpV4MessageType.EchoRequest : (byte)IcmpV6MessageType.EchoRequest, - Code = 0, - HeaderChecksum = 0, - Identifier = config.Identifier, - SequenceNumber = 0, - }; - - config.SendBuffer = CreateSendMessageBuffer(header, buffer); - return config; + bool ipv4 = address.AddressFamily == AddressFamily.InterNetwork; + + return new SocketConfig( + new IPEndPoint(address, 0), timeout, options, + ipv4, ipv4 ? ProtocolType.Icmp : ProtocolType.IcmpV6, id, + CreateSendMessageBuffer(new IcmpHeader() + { + Type = ipv4 ? (byte)IcmpV4MessageType.EchoRequest : (byte)IcmpV6MessageType.EchoRequest, + Identifier = id, + }, buffer)); } private Socket GetRawSocket(SocketConfig socketConfig) @@ -105,7 +97,9 @@ private Socket GetRawSocket(SocketConfig socketConfig) return socket; } - private bool TryGetPingReply(SocketConfig socketConfig, byte[] receiveBuffer, int bytesReceived, Stopwatch sw, ref int ipHeaderLength, out PingReply reply) + private bool TryGetPingReply( + SocketConfig socketConfig, byte[] receiveBuffer, int bytesReceived, Stopwatch sw, ref int ipHeaderLength, + [NotNullWhen(true)] out PingReply? reply) { byte type, code; reply = null; @@ -151,7 +145,7 @@ private bool TryGetPingReply(SocketConfig socketConfig, byte[] receiveBuffer, in return true; } - private PingReply SendIcmpEchoRequestOverRawSocket(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private PingReply SendIcmpEchoRequestOverRawSocket(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { SocketConfig socketConfig = GetSocketConfig(address, buffer, timeout, options); using (Socket socket = GetRawSocket(socketConfig)) @@ -190,7 +184,7 @@ private PingReply SendIcmpEchoRequestOverRawSocket(IPAddress address, byte[] buf continue; // Not enough bytes to reconstruct IP header + ICMP header. } - if (TryGetPingReply(socketConfig, receiveBuffer, bytesReceived, sw, ref ipHeaderLength, out PingReply reply)) + if (TryGetPingReply(socketConfig, receiveBuffer, bytesReceived, sw, ref ipHeaderLength, out PingReply? reply)) { return reply; } @@ -201,7 +195,7 @@ private PingReply SendIcmpEchoRequestOverRawSocket(IPAddress address, byte[] buf } } - private async Task SendIcmpEchoRequestOverRawSocketAsync(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private async Task SendIcmpEchoRequestOverRawSocketAsync(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { SocketConfig socketConfig = GetSocketConfig(address, buffer, timeout, options); using (Socket socket = GetRawSocket(socketConfig)) @@ -242,7 +236,7 @@ await socket.SendToAsync( continue; // Not enough bytes to reconstruct IP header + ICMP header. } - if (TryGetPingReply(socketConfig, receiveBuffer, bytesReceived, sw, ref ipHeaderLength, out PingReply reply)) + if (TryGetPingReply(socketConfig, receiveBuffer, bytesReceived, sw, ref ipHeaderLength, out PingReply? reply)) { return reply; } @@ -253,10 +247,10 @@ await socket.SendToAsync( } } - private Process GetPingProcess(IPAddress address, byte[] buffer, PingOptions options) + private Process GetPingProcess(IPAddress address, byte[] buffer, PingOptions? options) { bool isIpv4 = address.AddressFamily == AddressFamily.InterNetwork; - string pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath; + string? pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath; if (pingExecutable == null) { throw new PlatformNotSupportedException(SR.net_ping_utility_not_found); @@ -276,7 +270,7 @@ private Process GetPingProcess(IPAddress address, byte[] buffer, PingOptions opt return new Process() { StartInfo = psi }; } - private PingReply SendWithPingUtility(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private PingReply SendWithPingUtility(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { using (Process p = GetPingProcess(address, buffer, options)) { @@ -299,7 +293,7 @@ private PingReply SendWithPingUtility(IPAddress address, byte[] buffer, int time } } - private async Task SendWithPingUtilityAsync(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private async Task SendWithPingUtilityAsync(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { using (Process p = GetPingProcess(address, buffer, options)) { @@ -381,13 +375,24 @@ internal struct IcmpHeader // and no validation is performed. private class SocketConfig { + public SocketConfig(EndPoint endPoint, int timeout, PingOptions? options, bool isIPv4, ProtocolType protocolType, ushort id, byte[] sendBuffer) + { + EndPoint = endPoint; + Timeout = timeout; + Options = options; + IsIpv4 = isIPv4; + ProtocolType = protocolType; + Identifier = id; + SendBuffer = sendBuffer; + } + public EndPoint EndPoint; - public PingOptions Options; - public ushort Identifier; - public bool IsIpv4; - public ProtocolType ProtocolType; - public int Timeout; - public byte[] SendBuffer; + public readonly int Timeout; + public readonly PingOptions? Options; + public readonly ushort Identifier; + public readonly bool IsIpv4; + public readonly ProtocolType ProtocolType; + public readonly byte[] SendBuffer; } private static unsafe byte[] CreateSendMessageBuffer(IcmpHeader header, byte[] payload) diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs index fd4881dbf36ea..83a4ae6b1a4bb 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs @@ -23,22 +23,22 @@ public partial class Ping private int _sendSize = 0; // Needed to determine what the reply size is for ipv6 in callback. private bool _ipv6 = false; - private ManualResetEvent _pingEvent; - private RegisteredWaitHandle _registeredWait; - private SafeLocalAllocHandle _requestBuffer; - private SafeLocalAllocHandle _replyBuffer; - private Interop.IpHlpApi.SafeCloseIcmpHandle _handlePingV4; - private Interop.IpHlpApi.SafeCloseIcmpHandle _handlePingV6; - private TaskCompletionSource _taskCompletionSource; - - private PingReply SendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private ManualResetEvent? _pingEvent; + private RegisteredWaitHandle? _registeredWait; + private SafeLocalAllocHandle? _requestBuffer; + private SafeLocalAllocHandle? _replyBuffer; + private Interop.IpHlpApi.SafeCloseIcmpHandle? _handlePingV4; + private Interop.IpHlpApi.SafeCloseIcmpHandle? _handlePingV6; + private TaskCompletionSource? _taskCompletionSource; + + private PingReply SendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { // Since isAsync == false, DoSendPingCore will execute synchronously and return a completed // Task - so no blocking here return DoSendPingCore(address, buffer, timeout, options, isAsync: false).GetAwaiter().GetResult(); } - private Task SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions options) + private Task SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions? options) { // Since isAsync == true, DoSendPingCore will execute asynchronously and return an active Task return DoSendPingCore(address, buffer, timeout, options, isAsync: true); @@ -46,9 +46,9 @@ private Task SendPingAsyncCore(IPAddress address, byte[] buffer, int // Any exceptions that escape synchronously will be caught by the caller and wrapped in a PingException. // We do not need to or want to capture such exceptions into the returned task. - private Task DoSendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions options, bool isAsync) + private Task DoSendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions? options, bool isAsync) { - TaskCompletionSource tcs = null; + TaskCompletionSource? tcs = null; if (isAsync) { _taskCompletionSource = tcs = new TaskCompletionSource(); @@ -97,8 +97,10 @@ private Task DoSendPingCore(IPAddress address, byte[] buffer, int tim } } - if (isAsync) + if (tcs != null) + { return tcs.Task; + } Cleanup(isAsync); return Task.FromResult(CreatePingReply()); @@ -115,7 +117,7 @@ private void RegisterWaitHandle() _pingEvent.Reset(); } - _registeredWait = ThreadPool.RegisterWaitForSingleObject(_pingEvent, (state, _) => ((Ping)state).PingCallback(), this, -1, true); + _registeredWait = ThreadPool.RegisterWaitForSingleObject(_pingEvent, (state, _) => ((Ping)state!).PingCallback(), this, -1, true); } private void UnregisterWaitHandle() @@ -136,7 +138,7 @@ private SafeWaitHandle GetWaitHandle(bool async) { if (async) { - return _pingEvent.GetSafeWaitHandle(); + return _pingEvent!.GetSafeWaitHandle(); } return s_nullSafeWaitHandle; @@ -164,23 +166,23 @@ private void InitialiseIcmpHandle() } } - private int SendEcho(IPAddress address, byte[] buffer, int timeout, PingOptions options, bool isAsync) + private int SendEcho(IPAddress address, byte[] buffer, int timeout, PingOptions? options, bool isAsync) { Interop.IpHlpApi.IPOptions ipOptions = new Interop.IpHlpApi.IPOptions(options); if (!_ipv6) { return (int)Interop.IpHlpApi.IcmpSendEcho2( - _handlePingV4, + _handlePingV4!, GetWaitHandle(isAsync), IntPtr.Zero, IntPtr.Zero, #pragma warning disable CS0618 // Address is marked obsolete (uint)address.Address, #pragma warning restore CS0618 - _requestBuffer, + _requestBuffer!, (ushort)buffer.Length, ref ipOptions, - _replyBuffer, + _replyBuffer!, MaxUdpPacket, (uint)timeout); } @@ -190,23 +192,23 @@ private int SendEcho(IPAddress address, byte[] buffer, int timeout, PingOptions byte[] sourceAddr = new byte[28]; return (int)Interop.IpHlpApi.Icmp6SendEcho2( - _handlePingV6, + _handlePingV6!, GetWaitHandle(isAsync), IntPtr.Zero, IntPtr.Zero, sourceAddr, remoteAddr.Buffer, - _requestBuffer, + _requestBuffer!, (ushort)buffer.Length, ref ipOptions, - _replyBuffer, + _replyBuffer!, MaxUdpPacket, (uint)timeout); } private PingReply CreatePingReply() { - SafeLocalAllocHandle buffer = _replyBuffer; + SafeLocalAllocHandle buffer = _replyBuffer!; // Marshals and constructs new reply. if (_ipv6) @@ -261,11 +263,12 @@ partial void InternalDisposeCore() // Private callback invoked when icmpsendecho APIs succeed. private void PingCallback() { - TaskCompletionSource tcs = _taskCompletionSource; + TaskCompletionSource? tcs = _taskCompletionSource; _taskCompletionSource = null; + Debug.Assert(tcs != null); - PingReply reply = null; - Exception error = null; + PingReply? reply = null; + Exception? error = null; bool canceled = false; try @@ -345,7 +348,7 @@ private static PingReply CreatePingReplyFromIcmpEchoReply(Interop.IpHlpApi.IcmpE IPStatus ipStatus = GetStatusFromCode((int)reply.status); long rtt; - PingOptions options; + PingOptions? options; byte[] buffer; if (ipStatus == IPStatus.Success) @@ -358,8 +361,8 @@ private static PingReply CreatePingReplyFromIcmpEchoReply(Interop.IpHlpApi.IcmpE } else { - rtt = default(long); - options = default(PingOptions); + rtt = 0; + options = null; buffer = Array.Empty(); } @@ -383,11 +386,11 @@ private static PingReply CreatePingReplyFromIcmp6EchoReply(Interop.IpHlpApi.Icmp } else { - rtt = default(long); + rtt = 0; buffer = Array.Empty(); } - return new PingReply(address, default(PingOptions), ipStatus, rtt, buffer); + return new PingReply(address, null, ipStatus, rtt, buffer); } static partial void InitializeSockets() diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs index 48cc2ea9a5ad0..1388a8b0554b8 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs @@ -17,9 +17,9 @@ public partial class Ping : Component private const int MaxBufferSize = 65500; // Artificial constraint due to win32 api limitations. private readonly ManualResetEventSlim _lockObject = new ManualResetEventSlim(initialState: true); // doubles as the ability to wait on the current operation - private SendOrPostCallback _onPingCompletedDelegate; - private bool _disposeRequested = false; - private byte[] _defaultSendBuffer = null; + private SendOrPostCallback? _onPingCompletedDelegate; + private bool _disposeRequested; + private byte[]? _defaultSendBuffer; private bool _canceled; // Thread safety: @@ -40,7 +40,7 @@ public Ping() } } - private void CheckArgs(int timeout, byte[] buffer, PingOptions options) + private void CheckArgs(int timeout, byte[] buffer, PingOptions? options) { CheckDisposed(); if (buffer == null) @@ -59,7 +59,7 @@ private void CheckArgs(int timeout, byte[] buffer, PingOptions options) } } - private void CheckArgs(IPAddress address, int timeout, byte[] buffer, PingOptions options) + private void CheckArgs(IPAddress address, int timeout, byte[] buffer, PingOptions? options) { CheckArgs(timeout, buffer, options); @@ -164,7 +164,7 @@ protected override void Dispose(bool disposing) } } - public event PingCompletedEventHandler PingCompleted; + public event PingCompletedEventHandler? PingCompleted; protected void OnPingCompleted(PingCompletedEventArgs e) { @@ -201,7 +201,7 @@ public PingReply Send(IPAddress address, int timeout, byte[] buffer) return Send(address, timeout, buffer, null); } - public PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options) + public PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions? options) { if (string.IsNullOrEmpty(hostNameOrAddress)) { @@ -218,7 +218,7 @@ public PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer, Ping return GetAddressAndSend(hostNameOrAddress, timeout, buffer, options); } - public PingReply Send(IPAddress address, int timeout, byte[] buffer, PingOptions options) + public PingReply Send(IPAddress address, int timeout, byte[] buffer, PingOptions? options) { CheckArgs(address, timeout, buffer, options); @@ -241,53 +241,53 @@ public PingReply Send(IPAddress address, int timeout, byte[] buffer, PingOptions } } - public void SendAsync(string hostNameOrAddress, object userToken) + public void SendAsync(string hostNameOrAddress, object? userToken) { SendAsync(hostNameOrAddress, DefaultTimeout, DefaultSendBuffer, userToken); } - public void SendAsync(string hostNameOrAddress, int timeout, object userToken) + public void SendAsync(string hostNameOrAddress, int timeout, object? userToken) { SendAsync(hostNameOrAddress, timeout, DefaultSendBuffer, userToken); } - public void SendAsync(IPAddress address, object userToken) + public void SendAsync(IPAddress address, object? userToken) { SendAsync(address, DefaultTimeout, DefaultSendBuffer, userToken); } - public void SendAsync(IPAddress address, int timeout, object userToken) + public void SendAsync(IPAddress address, int timeout, object? userToken) { SendAsync(address, timeout, DefaultSendBuffer, userToken); } - public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, object userToken) + public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, object? userToken) { SendAsync(hostNameOrAddress, timeout, buffer, null, userToken); } - public void SendAsync(IPAddress address, int timeout, byte[] buffer, object userToken) + public void SendAsync(IPAddress address, int timeout, byte[] buffer, object? userToken) { SendAsync(address, timeout, buffer, null, userToken); } - public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options, object userToken) + public void SendAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions? options, object? userToken) { TranslateTaskToEap(userToken, SendPingAsync(hostNameOrAddress, timeout, buffer, options)); } - public void SendAsync(IPAddress address, int timeout, byte[] buffer, PingOptions options, object userToken) + public void SendAsync(IPAddress address, int timeout, byte[] buffer, PingOptions? options, object? userToken) { TranslateTaskToEap(userToken, SendPingAsync(address, timeout, buffer, options)); } - private void TranslateTaskToEap(object userToken, Task pingTask) + private void TranslateTaskToEap(object? userToken, Task pingTask) { pingTask.ContinueWith((t, state) => { - var asyncOp = (AsyncOperation)state; + var asyncOp = (AsyncOperation)state!; var e = new PingCompletedEventArgs(t.IsCompletedSuccessfully ? t.Result : null, t.Exception, t.IsCanceled, asyncOp.UserSuppliedState); - SendOrPostCallback callback = _onPingCompletedDelegate ?? (_onPingCompletedDelegate = new SendOrPostCallback(o => { OnPingCompleted((PingCompletedEventArgs)o); })); + SendOrPostCallback callback = _onPingCompletedDelegate ?? (_onPingCompletedDelegate = new SendOrPostCallback(o => { OnPingCompleted((PingCompletedEventArgs)o!); })); asyncOp.PostOperationCompleted(callback, e); }, AsyncOperationManager.CreateOperation(userToken), CancellationToken.None, TaskContinuationOptions.DenyChildAttach, TaskScheduler.Default); } @@ -322,13 +322,13 @@ public Task SendPingAsync(string hostNameOrAddress, int timeout, byte return SendPingAsync(hostNameOrAddress, timeout, buffer, null); } - public Task SendPingAsync(IPAddress address, int timeout, byte[] buffer, PingOptions options) + public Task SendPingAsync(IPAddress address, int timeout, byte[] buffer, PingOptions? options) { CheckArgs(address, timeout, buffer, options); return SendPingAsyncInternal(address, timeout, buffer, options); } - private async Task SendPingAsyncInternal(IPAddress address, int timeout, byte[] buffer, PingOptions options) + private async Task SendPingAsyncInternal(IPAddress address, int timeout, byte[] buffer, PingOptions? options) { // Need to snapshot the address here, so we're sure that it's not changed between now // and the operation, and to be sure that IPAddress.ToString() is called and not some override. @@ -350,7 +350,7 @@ private async Task SendPingAsyncInternal(IPAddress address, int timeo } } - public Task SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options) + public Task SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions? options) { if (string.IsNullOrEmpty(hostNameOrAddress)) { @@ -384,7 +384,7 @@ public void SendAsyncCancel() _lockObject.Wait(); } - private PingReply GetAddressAndSend(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options) + private PingReply GetAddressAndSend(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions? options) { CheckStart(); try @@ -402,7 +402,7 @@ private PingReply GetAddressAndSend(string hostNameOrAddress, int timeout, byte[ } } - private async Task GetAddressAndSendAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options) + private async Task GetAddressAndSendAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions? options) { CheckStart(); try diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingCompletedEventArgs.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingCompletedEventArgs.cs index 6091e442f28ff..db183b80b970b 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingCompletedEventArgs.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingCompletedEventArgs.cs @@ -10,11 +10,11 @@ namespace System.Net.NetworkInformation public class PingCompletedEventArgs : AsyncCompletedEventArgs { - internal PingCompletedEventArgs(PingReply reply, Exception error, bool cancelled, object userToken) : base(error, cancelled, userToken) + internal PingCompletedEventArgs(PingReply? reply, Exception? error, bool cancelled, object? userToken) : base(error, cancelled, userToken) { Reply = reply; } - public PingReply Reply { get; } + public PingReply? Reply { get; } } } diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingException.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingException.cs index 0679fee87e5c1..c36a7eb5fc6b7 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingException.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingException.cs @@ -10,12 +10,12 @@ namespace System.Net.NetworkInformation [System.Runtime.CompilerServices.TypeForwardedFrom("System, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")] public class PingException : InvalidOperationException { - public PingException(string message) : + public PingException(string? message) : base(message) { } - public PingException(string message, Exception innerException) : + public PingException(string? message, Exception? innerException) : base(message, innerException) { } diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingReply.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingReply.cs index cb8e0359056c8..618d68d982c2a 100644 --- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingReply.cs +++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingReply.cs @@ -6,34 +6,28 @@ namespace System.Net.NetworkInformation { public class PingReply { - private readonly IPAddress _address; - private readonly PingOptions _options; - private readonly IPStatus _ipStatus; - private readonly long _rtt; - private readonly byte[] _buffer; - internal PingReply( IPAddress address, - PingOptions options, + PingOptions? options, IPStatus ipStatus, long rtt, byte[] buffer) { - _address = address; - _options = options; - _ipStatus = ipStatus; - _rtt = rtt; - _buffer = buffer; + Address = address; + Options = options; + Status = ipStatus; + RoundtripTime = rtt; + Buffer = buffer; } - public IPStatus Status { get { return _ipStatus; } } + public IPStatus Status { get; } - public IPAddress Address { get { return _address; } } + public IPAddress Address { get; } - public long RoundtripTime { get { return _rtt; } } + public long RoundtripTime { get; } - public PingOptions Options { get { return _options; } } + public PingOptions? Options { get; } - public byte[] Buffer { get { return _buffer; } } + public byte[] Buffer { get; } } }