Ping in monotouch (ICMP requests)

baramusebaramuse USMember, Beta ✭✭
edited November 2012 in Xamarin.iOS

Hi,

Short version :

  • read and thought ICMP Ping were impossible in monotouch due to raw level socket denied access
  • found it was actually possible to get non-privileged ICMP socket with iOs
  • found a pure C# ICMP Ping request implementation, changed the socket access level to match iOs restriction
  • worked like a charm
  • shared it here
  • make it available in monotouch ?

Full one :

I was looking for a solution for sending Ping requests with monotouch, and have read a lot about it.
So from what I understood the base problem for implemting a Ping request on monotouch is that it requires the create a socket with raw access and that's not an option as it requires to have root access.
So that's why the System.Net.NetworkInformation.Ping is not available for monotouch (nor it is for Silverlight)
So there is NO WAY having a real Ping implementation with monotouch, have to fallback to the reachability classes...
BUT, in my further readings I've found the sample from Apple implementing Ping request in Cocoa/objc and in the readme, found a interesting precision :

On most platforms ping requires privileges (it's implemented with a raw IP socket). Mac OS X 10.2 and later, and all versions of iOS, include a special facility that allows you to ping without privileges. Specifically, you can open a special, non-privileged ICMP socket that allows you to send and receive pings. Look at the -[SimplePing startWithHostAddress] method for the details.

Oh then that's nice, we actually CAN open a socket for sending ICMP request on iOs!!
So I went looking for a pure C# implementation of ICMP request and found a really interesting reading about pure socket programming and it came along with its sources

So, I brought them down, created a monotouch project, launched a ping request and... FAILURE : access denied... but that was expected.
So I changed that line (RawSocketPing.cs at line 177) :
pingSocket = new Socket(destEndPoint.AddressFamily, SocketType.Raw, ProtocolType.Icmp);
to that :
pingSocket = new Socket(destEndPoint.AddressFamily, SocketType.Dgram, ProtocolType.Icmp);

And that worked like a charm.....

So! (finally) is there a way of getting a "real" Ping in monotouch ?

Cheers !!

Posts

  • RolfBjarneKvingeRolfBjarneKvinge USXamarin Team Xamurai

    Can you add this information to this bug report: https://bugzilla.xamarin.com/show_bug.cgi?id=964?

    Then someone will eventually get around to put it inside the class libraries.

  • baramusebaramuse USMember, Beta ✭✭

    Done !

  • CokaricCokaric HRMember, Beta
    edited March 2013

    I need the same thing for monodroid. We tried what you have posted here but it does not work. Any other suggestions?

    I still receive msg
    FAILURE : access denied.

    Thanks,
    Cokaric

  • baramusebaramuse USMember, Beta ✭✭

    @cokaric : Indeed, This may sounds strange, but Android does not give you access to SocketType.Dgram while iOs seems to !

    For Android I end up issuing a system cmd Ping :

    Runtime r = Runtime.GetRuntime(); Process p = r.Exec(string.Format("ping -c {0} {1}", PingCount, PingHost)); p.WaitFor(); int exit = p.ExitValue();

  • TommyBaggettTommyBaggett USUniversity ✭✭✭

    Hi @baramuse and @Cokaric, following up on this thread in case someone else runs across it looking for a ping-type solution for Android. I had problems getting your solution to work, but using the URLConnection class worked for me. If it fails to connect to the specified URL, an exception is thrown, which causes the code to skip updating the connection status.

        public enum NetworkStatus {
            NotReachable,
            ReachableViaCarrierDataNetwork,
            ReachableViaWiFiNetwork
        }
    
            public NetworkStatus RemoteHostStatus {
                get {
                    NetworkStatus result = NetworkStatus.NotReachable;
    
                    try
                    {
                        URL testUrl = new URL (hostName);
                        URLConnection connection = testUrl.OpenConnection ();
                        connection.ConnectTimeout = 10000;
                        connection.Connect ();
    
                        UpdateConnectionStatus ();
                        result = networkStatus;
                    }
                    catch (System.Exception e)
                    {
                        System.Console.WriteLine (e.ToString ());
                    }
                    return result;
                }
            }
    
            void UpdateConnectionStatus ()
            {
                // Default to "not reachable"
                networkStatus = NetworkStatus.NotReachable;
    
                var connectivityManager = (Android.Net.ConnectivityManager)activity.GetSystemService (Context.ConnectivityService);
                var activeConnection = connectivityManager.ActiveNetworkInfo;
                if (activeConnection != null && activeConnection.IsConnected) {
                    var mobileState = connectivityManager.GetNetworkInfo (Android.Net.ConnectivityType.Mobile).GetState ();
                    if (mobileState == Android.Net.NetworkInfo.State.Connected) {
                        networkStatus = NetworkStatus.ReachableViaCarrierDataNetwork;
                    } else {
                        var wifiState = connectivityManager.GetNetworkInfo (Android.Net.ConnectivityType.Wifi).GetState ();
                        if (wifiState == Android.Net.NetworkInfo.State.Connected) {
                            networkStatus = NetworkStatus.ReachableViaWiFiNetwork;
                        }
                    }
                }
            }
    
Sign In or Register to comment.