예제 #1
0
        private Process GetPingProcess(IPAddress address, byte[] buffer, int timeout, PingOptions?options)
        {
            bool   isIpv4         = address.AddressFamily == AddressFamily.InterNetwork;
            string?pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath;

            if (pingExecutable == null)
            {
                throw new PlatformNotSupportedException(SR.net_ping_utility_not_found);
            }

            UnixCommandLinePing.PingFragmentOptions fragmentOption = UnixCommandLinePing.PingFragmentOptions.Default;
            if (options != null && address.AddressFamily == AddressFamily.InterNetwork)
            {
                fragmentOption = options.DontFragment ? UnixCommandLinePing.PingFragmentOptions.Do : UnixCommandLinePing.PingFragmentOptions.Dont;
            }

            string processArgs = UnixCommandLinePing.ConstructCommandLine(buffer.Length, timeout, address.ToString(), isIpv4, options?.Ttl ?? 0, fragmentOption);

            ProcessStartInfo psi = new ProcessStartInfo(pingExecutable, processArgs);

            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError  = true;
            // Set LC_ALL=C to make sure to get ping output which is not affected by locale environment variables such as LANG and LC_MESSAGES.
            psi.EnvironmentVariables["LC_ALL"] = "C";
            return(new Process()
            {
                StartInfo = psi
            });
        }
예제 #2
0
        private Process GetPingProcess(IPAddress address, byte[] buffer, int timeout, PingOptions?options)
        {
            bool   isIpv4         = address.AddressFamily == AddressFamily.InterNetwork;
            string?pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath;

            if (pingExecutable == null)
            {
                throw new PlatformNotSupportedException(SR.net_ping_utility_not_found);
            }

            UnixCommandLinePing.PingFragmentOptions fragmentOption = UnixCommandLinePing.PingFragmentOptions.Default;
            if (options != null && address.AddressFamily == AddressFamily.InterNetwork)
            {
                fragmentOption = options.DontFragment ? UnixCommandLinePing.PingFragmentOptions.Do : UnixCommandLinePing.PingFragmentOptions.Dont;
            }

            string processArgs = UnixCommandLinePing.ConstructCommandLine(buffer.Length, timeout, address.ToString(), isIpv4, options?.Ttl ?? 0, fragmentOption);

            ProcessStartInfo psi = new ProcessStartInfo(pingExecutable, processArgs);

            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError  = true;
            return(new Process()
            {
                StartInfo = psi
            });
        }
예제 #3
0
        private PingReply ParsePingUtilityOutput(IPAddress address, string output)
        {
            long rtt = UnixCommandLinePing.ParseRoundTripTime(output);

            return(new PingReply(
                       address,
                       null, // Ping utility cannot accommodate these, return null to indicate they were ignored.
                       IPStatus.Success,
                       rtt,
                       Array.Empty <byte>())); // Ping utility doesn't deliver this info.
        }
예제 #4
0
        private Process GetPingProcess(IPAddress address, byte[] buffer)
        {
            bool   isIpv4         = address.AddressFamily == AddressFamily.InterNetwork;
            string pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath;

            if (pingExecutable == null)
            {
                throw new PlatformNotSupportedException(SR.net_ping_utility_not_found);
            }

            string           processArgs = UnixCommandLinePing.ConstructCommandLine(buffer.Length, address.ToString(), isIpv4);
            ProcessStartInfo psi         = new ProcessStartInfo(pingExecutable, processArgs);

            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError  = true;
            return(new Process()
            {
                StartInfo = psi
            });
        }
예제 #5
0
        private static PingReply ParsePingUtilityOutput(IPAddress address, int exitCode, string stdout)
        {
            // Throw timeout for known failure return codes from ping functions.
            if (exitCode == 1 || exitCode == 2)
            {
                // TTL exceeded may have occured
                if (TryParseTtlExceeded(stdout, out PingReply? reply))
                {
                    return(reply !);
                }

                // otherwise assume timeout
                return(CreatePingReply(IPStatus.TimedOut));
            }

            // On success, report RTT
            long rtt = UnixCommandLinePing.ParseRoundTripTime(stdout);

            return(CreatePingReply(IPStatus.Success, address, rtt));
        }
예제 #6
0
        private Process GetPingProcess(IPAddress address, byte[] buffer, int timeout, PingOptions?options)
        {
            bool   isIpv4         = address.AddressFamily == AddressFamily.InterNetwork;
            string?pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath;

            if (pingExecutable == null)
            {
                throw new PlatformNotSupportedException(SR.net_ping_utility_not_found);
            }

            // although the ping utility supports custom pattern via -p option, it supports
            // specifying only up to 16B pattern which repeats in the payload. The option also might
            // not be present in all distributions, so we forbid ping payload in general.
            if (buffer != DefaultSendBuffer && buffer != Array.Empty <byte>())
            {
                throw new PlatformNotSupportedException(SR.net_ping_utility_custom_payload);
            }

            UnixCommandLinePing.PingFragmentOptions fragmentOption = UnixCommandLinePing.PingFragmentOptions.Default;
            if (options != null && address.AddressFamily == AddressFamily.InterNetwork)
            {
                fragmentOption = options.DontFragment ? UnixCommandLinePing.PingFragmentOptions.Do : UnixCommandLinePing.PingFragmentOptions.Dont;
            }

            string processArgs = UnixCommandLinePing.ConstructCommandLine(buffer.Length, timeout, address.ToString(), isIpv4, options?.Ttl ?? 0, fragmentOption);

            ProcessStartInfo psi = new ProcessStartInfo(pingExecutable, processArgs);

            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError  = true;
            // Set LC_ALL=C to make sure to get ping output which is not affected by locale environment variables such as LANG and LC_MESSAGES.
            psi.EnvironmentVariables["LC_ALL"] = "C";
            return(new Process()
            {
                StartInfo = psi
            });
        }
예제 #7
0
        private async Task <PingReply> SendWithPingUtility(IPAddress address, byte[] buffer, int timeout, PingOptions options)
        {
            bool   isIpv4         = address.AddressFamily == AddressFamily.InterNetwork;
            string pingExecutable = isIpv4 ? UnixCommandLinePing.Ping4UtilityPath : UnixCommandLinePing.Ping6UtilityPath;

            if (pingExecutable == null)
            {
                throw new PlatformNotSupportedException(SR.net_ping_utility_not_found);
            }

            string           processArgs = UnixCommandLinePing.ConstructCommandLine(buffer.Length, address.ToString(), isIpv4);
            ProcessStartInfo psi         = new ProcessStartInfo(pingExecutable, processArgs);

            psi.RedirectStandardOutput = true;
            psi.RedirectStandardError  = true;
            Process p = new Process()
            {
                StartInfo = psi
            };

            var processCompletion = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously);

            p.EnableRaisingEvents = true;
            p.Exited += (s, e) => processCompletion.SetResult(true);
            p.Start();
            var  cts         = new CancellationTokenSource();
            Task timeoutTask = Task.Delay(timeout, cts.Token);

            Task finished = await Task.WhenAny(processCompletion.Task, timeoutTask).ConfigureAwait(false);

            if (finished == timeoutTask && !p.HasExited)
            {
                // Try to kill the ping process if it didn't return. If it is already in the process of exiting, a Win32Exception will be thrown.
                try
                {
                    p.Kill();
                }
                catch (Win32Exception) { }
                return(CreateTimedOutPingReply());
            }
            else
            {
                cts.Cancel();
                if (p.ExitCode != 0)
                {
                    // This means no reply was received, although transmission may have been successful.
                    return(CreateTimedOutPingReply());
                }

                try
                {
                    string output = await p.StandardOutput.ReadToEndAsync().ConfigureAwait(false);

                    long rtt = UnixCommandLinePing.ParseRoundTripTime(output);
                    return(new PingReply(
                               address,
                               null, // Ping utility cannot accomodate these, return null to indicate they were ignored.
                               IPStatus.Success,
                               rtt,
                               Array.Empty <byte>())); // Ping utility doesn't deliver this info.
                }
                catch (Exception)
                {
                    // If the standard output cannot be successfully parsed, throw a generic PingException.
                    throw new PingException(SR.net_ping);
                }
            }
        }