Annotate System.Net.Ping for nullable reference types (#32131)
authorStephen Toub <stoub@microsoft.com>
Thu, 13 Feb 2020 01:44:17 +0000 (17:44 -0800)
committerGitHub <noreply@github.com>
Thu, 13 Feb 2020 01:44:17 +0000 (17:44 -0800)
12 files changed:
src/libraries/Common/src/Interop/Windows/IpHlpApi/Interop.ICMP.cs
src/libraries/Common/src/System/Net/NetworkInformation/UnixCommandLinePing.cs
src/libraries/Common/src/System/Net/SocketAddress.cs
src/libraries/System.Net.Ping/ref/System.Net.Ping.cs
src/libraries/System.Net.Ping/ref/System.Net.Ping.csproj
src/libraries/System.Net.Ping/src/System.Net.Ping.csproj
src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Unix.cs
src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.Windows.cs
src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs
src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingCompletedEventArgs.cs
src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingException.cs
src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/PingReply.cs

index 6705874..220ac34 100644 (file)
@@ -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 static partial class Interop
             internal byte optionsSize;
             internal IntPtr optionsData;
 
-            internal IPOptions(PingOptions options)
+            internal IPOptions(PingOptions? options)
             {
                 ttl = 128;
                 tos = 0;
index 3a5c413..0944538 100644 (file)
@@ -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 @@ namespace System.Net.NetworkInformation
         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<bool> s_isBusybox = new Lazy<bool>(() => 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 @@ namespace System.Net.NetworkInformation
         }
 
         // 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 @@ namespace System.Net.NetworkInformation
         /// <summary>
         /// The location of the IPv4 ping utility on the current machine.
         /// </summary>
-        public static string Ping4UtilityPath { get { return s_discoveredPing4UtilityPath; } }
+        public static string? Ping4UtilityPath { get { return s_discoveredPing4UtilityPath; } }
 
         /// <summary>
         /// The location of the IPv6 ping utility on the current machine.
         /// </summary>
-        public static string Ping6UtilityPath { get { return s_discoveredPing6UtilityPath; } }
+        public static string? Ping6UtilityPath { get { return s_discoveredPing6UtilityPath; } }
 
         /// <summary>
         /// Constructs command line arguments appropriate for the ping or ping6 utility.
index 310b8fc..a3a93bd 100644 (file)
@@ -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 @@ namespace System.Net.Internals
             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;
index 08e1c48..847b3ec 100644 (file)
@@ -37,34 +37,34 @@ namespace System.Net.NetworkInformation
     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<System.Net.NetworkInformation.PingReply> SendPingAsync(System.Net.IPAddress address) { throw null; }
         public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(System.Net.IPAddress address, int timeout) { throw null; }
         public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(System.Net.IPAddress address, int timeout, byte[] buffer) { throw null; }
-        public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options) { throw null; }
+        public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; }
         public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(string hostNameOrAddress) { throw null; }
         public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(string hostNameOrAddress, int timeout) { throw null; }
         public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer) { throw null; }
-        public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions options) { throw null; }
+        public System.Threading.Tasks.Task<System.Net.NetworkInformation.PingReply> 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 @@ namespace System.Net.NetworkInformation
     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 @@ namespace System.Net.NetworkInformation
         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; } }
     }
index 9d2579f..b91f824 100644 (file)
@@ -1,6 +1,7 @@
 <Project Sdk="Microsoft.NET.Sdk">
   <PropertyGroup>
     <TargetFrameworks>$(NetCoreAppCurrent)</TargetFrameworks>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="System.Net.Ping.cs" />
index 92871b7..36d2f01 100644 (file)
@@ -4,6 +4,7 @@
     <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
     <NoWarn>$(NoWarn);CS1573</NoWarn>
     <TargetFrameworks>$(NetCoreAppCurrent)-Windows_NT;$(NetCoreAppCurrent)-Unix</TargetFrameworks>
+    <Nullable>enable</Nullable>
   </PropertyGroup>
   <ItemGroup>
     <Compile Include="System\Net\NetworkInformation\IPStatus.cs" />
index 5b9fcb6..b0b008d 100644 (file)
@@ -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 @@ namespace System.Net.NetworkInformation
         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 @@ namespace System.Net.NetworkInformation
             return reply;
         }
 
-        private async Task<PingReply> SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions options)
+        private async Task<PingReply> SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions? options)
         {
             Task<PingReply> t = RawSocketPermissions.CanUseRawSockets(address.AddressFamily) ?
                     SendIcmpEchoRequestOverRawSocketAsync(address, buffer, timeout, options) :
@@ -45,32 +46,23 @@ namespace System.Net.NetworkInformation
             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 @@ namespace System.Net.NetworkInformation
             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 @@ namespace System.Net.NetworkInformation
             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 @@ namespace System.Net.NetworkInformation
                         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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        private async Task<PingReply> SendIcmpEchoRequestOverRawSocketAsync(IPAddress address, byte[] buffer, int timeout, PingOptions options)
+        private async Task<PingReply> 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 @@ namespace System.Net.NetworkInformation
                         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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        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 @@ namespace System.Net.NetworkInformation
             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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        private async Task<PingReply> SendWithPingUtilityAsync(IPAddress address, byte[] buffer, int timeout, PingOptions options)
+        private async Task<PingReply> SendWithPingUtilityAsync(IPAddress address, byte[] buffer, int timeout, PingOptions? options)
         {
             using (Process p = GetPingProcess(address, buffer, options))
             {
@@ -381,13 +375,24 @@ namespace System.Net.NetworkInformation
         // 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)
index fd4881d..83a4ae6 100644 (file)
@@ -23,22 +23,22 @@ namespace System.Net.NetworkInformation
 
         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<PingReply> _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<PingReply>? _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<PingReply> SendPingAsyncCore(IPAddress address, byte[] buffer, int timeout, PingOptions options)
+        private Task<PingReply> 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 @@ namespace System.Net.NetworkInformation
 
         // 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<PingReply> DoSendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions options, bool isAsync)
+        private Task<PingReply> DoSendPingCore(IPAddress address, byte[] buffer, int timeout, PingOptions? options, bool isAsync)
         {
-            TaskCompletionSource<PingReply> tcs = null;
+            TaskCompletionSource<PingReply>? tcs = null;
             if (isAsync)
             {
                 _taskCompletionSource = tcs = new TaskCompletionSource<PingReply>();
@@ -97,8 +97,10 @@ namespace System.Net.NetworkInformation
                 }
             }
 
-            if (isAsync)
+            if (tcs != null)
+            {
                 return tcs.Task;
+            }
 
             Cleanup(isAsync);
             return Task.FromResult(CreatePingReply());
@@ -115,7 +117,7 @@ namespace System.Net.NetworkInformation
                 _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 @@ namespace System.Net.NetworkInformation
         {
             if (async)
             {
-                return _pingEvent.GetSafeWaitHandle();
+                return _pingEvent!.GetSafeWaitHandle();
             }
 
             return s_nullSafeWaitHandle;
@@ -164,23 +166,23 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        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 @@ namespace System.Net.NetworkInformation
             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 @@ namespace System.Net.NetworkInformation
         // Private callback invoked when icmpsendecho APIs succeed.
         private void PingCallback()
         {
-            TaskCompletionSource<PingReply> tcs = _taskCompletionSource;
+            TaskCompletionSource<PingReply>? 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 @@ namespace System.Net.NetworkInformation
             IPStatus ipStatus = GetStatusFromCode((int)reply.status);
 
             long rtt;
-            PingOptions options;
+            PingOptions? options;
             byte[] buffer;
 
             if (ipStatus == IPStatus.Success)
@@ -358,8 +361,8 @@ namespace System.Net.NetworkInformation
             }
             else
             {
-                rtt = default(long);
-                options = default(PingOptions);
+                rtt = 0;
+                options = null;
                 buffer = Array.Empty<byte>();
             }
 
@@ -383,11 +386,11 @@ namespace System.Net.NetworkInformation
             }
             else
             {
-                rtt = default(long);
+                rtt = 0;
                 buffer = Array.Empty<byte>();
             }
 
-            return new PingReply(address, default(PingOptions), ipStatus, rtt, buffer);
+            return new PingReply(address, null, ipStatus, rtt, buffer);
         }
 
         static partial void InitializeSockets()
index 48cc2ea..1388a8b 100644 (file)
@@ -17,9 +17,9 @@ namespace System.Net.NetworkInformation
         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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        public event PingCompletedEventHandler PingCompleted;
+        public event PingCompletedEventHandler? PingCompleted;
 
         protected void OnPingCompleted(PingCompletedEventArgs e)
         {
@@ -201,7 +201,7 @@ namespace System.Net.NetworkInformation
             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 @@ namespace System.Net.NetworkInformation
             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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        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<PingReply> pingTask)
+        private void TranslateTaskToEap(object? userToken, Task<PingReply> 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 @@ namespace System.Net.NetworkInformation
             return SendPingAsync(hostNameOrAddress, timeout, buffer, null);
         }
 
-        public Task<PingReply> SendPingAsync(IPAddress address, int timeout, byte[] buffer, PingOptions options)
+        public Task<PingReply> SendPingAsync(IPAddress address, int timeout, byte[] buffer, PingOptions? options)
         {
             CheckArgs(address, timeout, buffer, options);
             return SendPingAsyncInternal(address, timeout, buffer, options);
         }
 
-        private async Task<PingReply> SendPingAsyncInternal(IPAddress address, int timeout, byte[] buffer, PingOptions options)
+        private async Task<PingReply> 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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        public Task<PingReply> SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options)
+        public Task<PingReply> SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions? options)
         {
             if (string.IsNullOrEmpty(hostNameOrAddress))
             {
@@ -384,7 +384,7 @@ namespace System.Net.NetworkInformation
             _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 @@ namespace System.Net.NetworkInformation
             }
         }
 
-        private async Task<PingReply> GetAddressAndSendAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions options)
+        private async Task<PingReply> GetAddressAndSendAsync(string hostNameOrAddress, int timeout, byte[] buffer, PingOptions? options)
         {
             CheckStart();
             try
index 6091e44..db183b8 100644 (file)
@@ -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; }
     }
 }
index 0679fee..c36a7eb 100644 (file)
@@ -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)
         {
         }
index cb8e035..618d68d 100644 (file)
@@ -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; }
     }
 }