Ping.cs :  » 2.6.4-mono-.net-core » System.Net » System » Net » NetworkInformation » C# / CSharp Open Source

Home
C# / CSharp Open Source
1.2.6.4 mono .net core
2.2.6.4 mono core
3.Aspect Oriented Frameworks
4.Bloggers
5.Build Systems
6.Business Application
7.Charting Reporting Tools
8.Chat Servers
9.Code Coverage Tools
10.Content Management Systems CMS
11.CRM ERP
12.Database
13.Development
14.Email
15.Forum
16.Game
17.GIS
18.GUI
19.IDEs
20.Installers Generators
21.Inversion of Control Dependency Injection
22.Issue Tracking
23.Logging Tools
24.Message
25.Mobile
26.Network Clients
27.Network Servers
28.Office
29.PDF
30.Persistence Frameworks
31.Portals
32.Profilers
33.Project Management
34.RSS RDF
35.Rule Engines
36.Script
37.Search Engines
38.Sound Audio
39.Source Control
40.SQL Clients
41.Template Engines
42.Testing
43.UML
44.Web Frameworks
45.Web Service
46.Web Testing
47.Wiki Engines
48.Windows Presentation Foundation
49.Workflows
50.XML Parsers
C# / C Sharp
C# / C Sharp by API
C# / CSharp Tutorial
C# / CSharp Open Source » 2.6.4 mono .net core » System.Net 
System.Net » System » Net » NetworkInformation » Ping.cs
//
// System.Net.NetworkInformation.Ping
//
// Authors:
//  Gonzalo Paniagua Javier (gonzalo@novell.com)
//  Atsushi Enomoto (atsushi@ximian.com)
//
// Copyright (c) 2006-2007 Novell, Inc. (http://www.novell.com)
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
// 
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
// 
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
#if NET_2_0
using System;
using System.IO;
using System.Text;
using System.Diagnostics;
using System.Globalization;
using System.ComponentModel;
using System.Net.Sockets;
using System.Security.Principal;
using System.Runtime.InteropServices;

namespace System.Net.NetworkInformation{
  [MonoTODO ("IPv6 support is missing")]
  public class Ping : Component, IDisposable
  {
    [StructLayout(LayoutKind.Sequential)]
    struct cap_user_header_t
    {
      public UInt32 version;
      public Int32 pid;
    };

    [StructLayout(LayoutKind.Sequential)]
    struct cap_user_data_t
    {
      public UInt32 effective;
      public UInt32 permitted;
      public UInt32 inheritable;
    }
    
    const int DefaultCount = 1;
    static readonly string [] PingBinPaths = new string [] {
      "/bin/ping",
      "/sbin/ping",
      "/usr/sbin/ping"
    };
    static readonly string PingBinPath;
    const int default_timeout = 4000; // 4 sec.
    const int identifier = 1; // no need to be const, but there's no place to change it.

    // This value is correct as of Linux kernel version 2.6.25.9
    // See /usr/include/linux/capability.h
    const UInt32 linux_cap_version = 0x20071026;
    
    static readonly byte [] default_buffer = new byte [0];
    static bool canSendPrivileged;
    

    BackgroundWorker worker;
    object user_async_state;
    
    public event PingCompletedEventHandler PingCompleted;
    
    static Ping ()
    {
      if (Environment.OSVersion.Platform == PlatformID.Unix) {
        CheckLinuxCapabilities ();
        if (!canSendPrivileged && WindowsIdentity.GetCurrent ().Name == "root")
          canSendPrivileged = true;
      
        // Since different Unix systems can have different path to bin, we try some
        // of the known ones.
        foreach (string ping_path in PingBinPaths)
          if (File.Exists (ping_path)) {
            PingBinPath = ping_path;
            break;
          }
      }
      else
        canSendPrivileged = true;

      if (PingBinPath == null)
        PingBinPath = "/bin/ping"; // default, fallback value
    }
    
    public Ping ()
    {
    }
  
    [DllImport ("libc", EntryPoint="capget")]
    static extern int capget (ref cap_user_header_t header, ref cap_user_data_t data);

    static void CheckLinuxCapabilities ()
    {
      try {
        cap_user_header_t header = new cap_user_header_t ();
        cap_user_data_t data = new cap_user_data_t ();

        header.version = linux_cap_version;

        int ret = -1;

        try {
          ret = capget (ref header, ref data);
        } catch (Exception) {
        }

        if (ret == -1)
          return;

        canSendPrivileged = (data.effective & (1 << 13)) != 0;
      } catch {
        canSendPrivileged = false;
      }
    }
    
    void IDisposable.Dispose ()
    {
    }

    protected void OnPingCompleted (PingCompletedEventArgs e)
    {
      if (PingCompleted != null)
        PingCompleted (this, e);
      user_async_state = null;
      worker = null;
    }

    // Sync

    public PingReply Send (IPAddress address)
    {
      return Send (address, default_timeout);
    }

    public PingReply Send (IPAddress address, int timeout)
    {
      return Send (address, timeout, default_buffer);
    }

    public PingReply Send (IPAddress address, int timeout, byte [] buffer)
    {
      return Send (address, timeout, buffer, new PingOptions ());
    }

    public PingReply Send (string hostNameOrAddress)
    {
      return Send (hostNameOrAddress, default_timeout);
    }

    public PingReply Send (string hostNameOrAddress, int timeout)
    {
      return Send (hostNameOrAddress, timeout, default_buffer);
    }

    public PingReply Send (string hostNameOrAddress, int timeout, byte [] buffer)
    {
      return Send (hostNameOrAddress, timeout, buffer, new PingOptions ());
    }

    public PingReply Send (string hostNameOrAddress, int timeout, byte [] buffer, PingOptions options)
    {
      IPAddress [] addresses = Dns.GetHostAddresses (hostNameOrAddress);
      return Send (addresses [0], timeout, buffer, options);
    }

    static IPAddress GetNonLoopbackIP ()
    {
      foreach (IPAddress addr in Dns.GetHostByName (Dns.GetHostName ()).AddressList)
        if (!IPAddress.IsLoopback (addr))
          return addr;
      throw new InvalidOperationException ("Could not resolve non-loopback IP address for localhost");
    }

    public PingReply Send (IPAddress address, int timeout, byte [] buffer, PingOptions options)
    {
      if (address == null)
        throw new ArgumentNullException ("address");
      if (timeout < 0)
        throw new ArgumentOutOfRangeException ("timeout", "timeout must be non-negative integer");
      if (buffer == null)
        throw new ArgumentNullException ("buffer");
      if (buffer.Length > 65500)
        throw new ArgumentException ("buffer");
      // options can be null.

      if (canSendPrivileged)
        return SendPrivileged (address, timeout, buffer, options);
      return SendUnprivileged (address, timeout, buffer, options);
    }

    private PingReply SendPrivileged (IPAddress address, int timeout, byte [] buffer, PingOptions options)
    {
      IPEndPoint target = new IPEndPoint (address, 0);
      IPEndPoint client = new IPEndPoint (GetNonLoopbackIP (), 0);

      // FIXME: support IPv6
      using (Socket s = new Socket (AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp)) {
        if (options != null) {
          s.DontFragment = options.DontFragment;
          s.Ttl = (short) options.Ttl;
        }
        s.SendTimeout = timeout;
        s.ReceiveTimeout = timeout;
        // not sure why Identifier = 0 is unacceptable ...
        IcmpMessage send = new IcmpMessage (8, 0, identifier, 0, buffer);
        byte [] bytes = send.GetBytes ();
        s.SendBufferSize = bytes.Length;
        s.SendTo (bytes, bytes.Length, SocketFlags.None, target);

        DateTime sentTime = DateTime.Now;

        // receive
        bytes = new byte [100];
        do {
          EndPoint endpoint = client;
          int error = 0;
          int rc = s.ReceiveFrom_nochecks_exc (bytes, 0, 100, SocketFlags.None,
              ref endpoint, false, out error);

          if (error != 0) {
            if (error == (int) SocketError.TimedOut) {
              return new PingReply (null, new byte [0], options, 0, IPStatus.TimedOut);
            }
            throw new NotSupportedException (String.Format ("Unexpected socket error during ping request: {0}", error));
          }
          long rtt = (long) (DateTime.Now - sentTime).TotalMilliseconds;
          int headerLength = (bytes [0] & 0xF) << 2;
          int bodyLength = rc - headerLength;

          // Ping reply to different request. discard it.
          if (!((IPEndPoint) endpoint).Address.Equals (target.Address)) {
            long t = timeout - rtt;
            if (t <= 0)
              return new PingReply (null, new byte [0], options, 0, IPStatus.TimedOut);
            s.ReceiveTimeout = (int) t;
            continue;
          }

          IcmpMessage recv = new IcmpMessage (bytes, headerLength, bodyLength);

          /* discard ping reply to different request or echo requests if running on same host. */
          if (recv.Identifier != identifier || recv.Type == 8) {
            long t = timeout - rtt;
            if (t <= 0)
              return new PingReply (null, new byte [0], options, 0, IPStatus.TimedOut);
            s.ReceiveTimeout = (int) t;
            continue; 
          }

          return new PingReply (address, recv.Data, options, rtt, recv.IPStatus);
        } while (true);
      }
    }

    private PingReply SendUnprivileged (IPAddress address, int timeout, byte [] buffer, PingOptions options)
    {
      DateTime sentTime = DateTime.Now;

      Process ping = new Process ();
      string args = BuildPingArgs (address, timeout, options);
      long trip_time = 0;

      ping.StartInfo.FileName = PingBinPath;
      ping.StartInfo.Arguments = args;

      ping.StartInfo.CreateNoWindow = true;
      ping.StartInfo.UseShellExecute = false;

      ping.StartInfo.RedirectStandardOutput = true;
      ping.StartInfo.RedirectStandardError = true;

      try {
        ping.Start ();

#pragma warning disable 219
      // No need to read stdout or stderr as long as the output is less than 4k on linux <= 2.6.11 and 65k after that
      //  string stdout = ping.StandardOutput.ReadToEnd ();
      //  string stderr = ping.StandardError.ReadToEnd ();
#pragma warning restore 219
        
        trip_time = (long) (DateTime.Now - sentTime).TotalMilliseconds;
        if (!ping.WaitForExit (timeout) || (ping.HasExited && ping.ExitCode == 2))
          return new PingReply (address, buffer, options, trip_time, IPStatus.TimedOut); 

        if (ping.ExitCode == 1)
          return new PingReply (address, buffer, options, trip_time, IPStatus.TtlExpired);
      } catch (Exception) {
        return new PingReply (address, buffer, options, trip_time, IPStatus.Unknown);
      } finally {
        if (ping != null) {
          if (!ping.HasExited)
            ping.Kill ();
          ping.Dispose ();
        }
      }

      return new PingReply (address, buffer, options, trip_time, IPStatus.Success);
    }

    // Async

    public void SendAsync (IPAddress address, int timeout, byte [] buffer, object userToken)
    {
      SendAsync (address, default_timeout, default_buffer, new PingOptions (), userToken);
    }

    public void SendAsync (IPAddress address, int timeout, object userToken)
    {
      SendAsync (address, default_timeout, default_buffer, userToken);
    }

    public void SendAsync (IPAddress address, object userToken)
    {
      SendAsync (address, default_timeout, userToken);
    }

    public void SendAsync (string hostNameOrAddress, int timeout, byte [] buffer, object userToken)
    {
      SendAsync (hostNameOrAddress, timeout, buffer, new PingOptions (), userToken);
    }

    public void SendAsync (string hostNameOrAddress, int timeout, byte [] buffer, PingOptions options, object userToken)
    {
      IPAddress address = Dns.GetHostEntry (hostNameOrAddress).AddressList [0];
      SendAsync (address, timeout, buffer, options, userToken);
    }

    public void SendAsync (string hostNameOrAddress, int timeout, object userToken)
    {
      SendAsync (hostNameOrAddress, timeout, default_buffer, userToken);
    }

    public void SendAsync (string hostNameOrAddress, object userToken)
    {
      SendAsync (hostNameOrAddress, default_timeout, userToken);
    }

    public void SendAsync (IPAddress address, int timeout, byte [] buffer, PingOptions options, object userToken)
    {
      if (worker != null)
        throw new InvalidOperationException ("Another SendAsync operation is in progress");

      worker = new BackgroundWorker ();
      worker.DoWork += delegate (object o, DoWorkEventArgs ea) {
        try {
          user_async_state = ea.Argument;
          ea.Result = Send (address, timeout, buffer, options);
        } catch (Exception ex) {
          ea.Result = ex;
        }
      };
      worker.WorkerSupportsCancellation = true;
      worker.RunWorkerCompleted += delegate (object o, RunWorkerCompletedEventArgs ea) {
        // Note that RunWorkerCompletedEventArgs.UserState cannot be used (LAMESPEC)
        OnPingCompleted (new PingCompletedEventArgs (ea.Error, ea.Cancelled, user_async_state, ea.Result as PingReply));
      };
      worker.RunWorkerAsync (userToken);
    }

    // SendAsyncCancel

    public void SendAsyncCancel ()
    {
      if (worker == null)
        throw new InvalidOperationException ("SendAsync operation is not in progress");
      worker.CancelAsync ();
    }

    // ICMP message

    class IcmpMessage
    {
      byte [] bytes;

      // received
      public IcmpMessage (byte [] bytes, int offset, int size)
      {
        this.bytes = new byte [size];
        Buffer.BlockCopy (bytes, offset, this.bytes, 0, size);
      }

      // to be sent
      public IcmpMessage (byte type, byte code, short identifier, short sequence, byte [] data)
      {
        bytes = new byte [data.Length + 8];
        bytes [0] = type;
        bytes [1] = code;
        bytes [4] = (byte) (identifier & 0xFF);
        bytes [5] = (byte) ((int) identifier >> 8);
        bytes [6] = (byte) (sequence & 0xFF);
        bytes [7] = (byte) ((int) sequence >> 8);
        Buffer.BlockCopy (data, 0, bytes, 8, data.Length);

        ushort checksum = ComputeChecksum (bytes);
        bytes [2] = (byte) (checksum & 0xFF);
        bytes [3] = (byte) ((int) checksum >> 8);
      }

      public byte Type {
        get { return bytes [0]; }
      }

      public byte Code {
        get { return bytes [1]; }
      }

      public byte Identifier {
        get { return (byte) (bytes [4] + (bytes [5] << 8)); }
      }

      public byte Sequence {
        get { return (byte) (bytes [6] + (bytes [7] << 8)); }
      }

      public byte [] Data {
        get {
          byte [] data = new byte [bytes.Length - 8];
          Buffer.BlockCopy (bytes, 0, data, 0, data.Length);
          return data;
        }
      }

      public byte [] GetBytes ()
      {
        return bytes;
      }

      static ushort ComputeChecksum (byte [] data)
      {
        uint ret = 0;
        for (int i = 0; i < data.Length; i += 2) {
          ushort us = i + 1 < data.Length ? data [i + 1] : (byte) 0;
          us <<= 8;
          us += data [i];
          ret += us;
        }
        ret = (ret >> 16) + (ret & 0xFFFF);
        return (ushort) ~ ret;
      }

      public IPStatus IPStatus {
        get {
          switch (Type) {
          case 0:
            return IPStatus.Success;
          case 3: // destination unreacheable
            switch (Code) {
            case 0:
              return IPStatus.DestinationNetworkUnreachable;
            case 1:
              return IPStatus.DestinationHostUnreachable;
            case 2:
              return IPStatus.DestinationProtocolUnreachable;
            case 3:
              return IPStatus.DestinationPortUnreachable;
            case 4:
              return IPStatus.BadOption; // FIXME: likely wrong
            case 5:
              return IPStatus.BadRoute; // not sure if it is correct
            }
            break;
          case 11:
            switch (Code) {
            case 0:
              return IPStatus.TimeExceeded;
            case 1:
              return IPStatus.TtlReassemblyTimeExceeded;
            }
            break;
          case 12:
            return IPStatus.ParameterProblem;
          case 4:
            return IPStatus.SourceQuench;
          case 8:
            return IPStatus.Success;
          }
          return IPStatus.Unknown;
          //throw new NotSupportedException (String.Format ("Unexpected pair of ICMP message type and code: type is {0} and code is {1}", Type, Code));
        }
      }
    }

    private string BuildPingArgs (IPAddress address, int timeout, PingOptions options)
    {
      CultureInfo culture = CultureInfo.InvariantCulture;
      StringBuilder args = new StringBuilder ();
      uint t = Convert.ToUInt32 (Math.Floor ((timeout + 1000) / 1000.0));
#if NET_2_0
      bool is_mac = ((int) Environment.OSVersion.Platform == 6);
      if (!is_mac)
#endif
        args.AppendFormat (culture, "-q -n -c {0} -w {1} -t {2} -M ", DefaultCount, t, options.Ttl);
#if NET_2_0
      else
        args.AppendFormat (culture, "-q -n -c {0} -t {1} -o -m {2} ", DefaultCount, t, options.Ttl);
      if (!is_mac)
#endif
        args.Append (options.DontFragment ? "do " : "dont ");
#if NET_2_0
      else if (options.DontFragment)
        args.Append ("-D ");
#endif

      args.Append (address.ToString ());

      return args.ToString ();
    }

  }
}
#endif

www.java2v.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.