Translate SocketError.MessageSize to IPStatus.PacketTooBig in Ping.SendPing[Async...
authorFilip Navara <navara@emclient.com>
Thu, 22 Jul 2021 20:22:49 +0000 (22:22 +0200)
committerGitHub <noreply@github.com>
Thu, 22 Jul 2021 20:22:49 +0000 (16:22 -0400)
* Translate SocketError.MessageSize to IPStatus.PacketTooBig in Ping.SendPing[Async]

* Address feedback

* Remove extra whitespace

src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.PingUtility.cs
src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.RawSocket.cs
src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs

index e5e3a89..74e85ca 100644 (file)
@@ -47,7 +47,7 @@ namespace System.Net.NetworkInformation
                 p.Start();
                 if (!p.WaitForExit(timeout) || p.ExitCode == 1 || p.ExitCode == 2)
                 {
-                    return CreateTimedOutPingReply();
+                    return CreatePingReply(IPStatus.TimedOut);
                 }
 
                 try
@@ -79,13 +79,13 @@ namespace System.Net.NetworkInformation
                 catch (TimeoutException)
                 {
                     p.Kill();
-                    return CreateTimedOutPingReply();
+                    return CreatePingReply(IPStatus.TimedOut);
                 }
 
                 if (p.ExitCode == 1 || p.ExitCode == 2)
                 {
                     // Throw timeout for known failure return codes from ping functions.
-                    return CreateTimedOutPingReply();
+                    return CreatePingReply(IPStatus.TimedOut);
                 }
 
                 try
index de34385..341c328 100644 (file)
@@ -187,9 +187,13 @@ namespace System.Net.NetworkInformation
                 catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
                 {
                 }
+                catch (SocketException ex) when (ex.SocketErrorCode == SocketError.MessageSize)
+                {
+                    return CreatePingReply(IPStatus.PacketTooBig);
+                }
 
                 // We have exceeded our timeout duration, and no reply has been received.
-                return CreateTimedOutPingReply();
+                return CreatePingReply(IPStatus.TimedOut);
             }
         }
 
@@ -239,6 +243,10 @@ namespace System.Net.NetworkInformation
                 catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
                 {
                 }
+                catch (SocketException ex) when (ex.SocketErrorCode == SocketError.MessageSize)
+                {
+                    return CreatePingReply(IPStatus.PacketTooBig);
+                }
                 catch (OperationCanceledException)
                 {
                 }
@@ -248,15 +256,15 @@ namespace System.Net.NetworkInformation
                 }
 
                 // We have exceeded our timeout duration, and no reply has been received.
-                return CreateTimedOutPingReply();
+                return CreatePingReply(IPStatus.TimedOut);
             }
         }
 
-        private static PingReply CreateTimedOutPingReply()
+        private static PingReply CreatePingReply(IPStatus status)
         {
             // Documentation indicates that you should only pay attention to the IPStatus value when
             // its value is not "Success", but the rest of these values match that of the Windows implementation.
-            return new PingReply(new IPAddress(0), null, IPStatus.TimedOut, 0, Array.Empty<byte>());
+            return new PingReply(new IPAddress(0), null, status, 0, Array.Empty<byte>());
         }
 
 #if DEBUG
index 74f14a2..22e2ccb 100644 (file)
@@ -647,6 +647,30 @@ namespace System.Net.NetworkInformation.Tests
                 });
         }
 
+        [Fact]
+        public async Task SendPingWithIPAddressAndBigSize()
+        {
+            IPAddress localIpAddress = TestSettings.GetLocalIPAddress();
+
+            using (Ping p = new Ping())
+            {
+                // Assert.DoesNotThrow
+                PingReply pingReply = await p.SendPingAsync(localIpAddress, TestSettings.PingTimeout, new byte[10001]);
+                
+                // Depending on platform the call may either succeed, report timeout or report too big packet. It
+                // should not throw wrapped SocketException though which is what this test guards.
+                //
+                // On Windows 10 the maximum ping size seems essentially limited to 65500 bytes and thus any buffer
+                // size on the loopback ping succeeds. On macOS anything bigger than 8184 will report packet too
+                // big error. On Linux/Unix the result differs for privileged and unprivileged processes and may
+                // change with different platform versions.
+                if (OperatingSystem.IsMacOS())
+                {
+                    Assert.Equal(IPStatus.PacketTooBig, pingReply.Status);
+                }
+            }
+        }
+
         [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
         [ActiveIssue("https://github.com/dotnet/runtime/issues/52617", TestPlatforms.iOS | TestPlatforms.tvOS | TestPlatforms.MacCatalyst)]
         public async Task SendPings_ReuseInstance_Hostname()