PING with ColdFusion and .NET
I was curious if were possible to ping a server using something other than the usual cfexecute and ping.exe. method. My first thought was surely java can do it. Feeling quite confident, I found a neat method in the InetAddress class called isReachable() that seemed to fit the bill. I happily wrote up a small test, ran the code, and quickly realized something was wrong.
<cfscript>
InetAddress = createObject("java", "java.net.InetAddress");
address = InetAddress.getByName("www.google.com");
isReachable = address.isReachable( 500 ); //timeout
WriteOutput( address.getHostName() &" ["& address.getHostAddress() &"] "&
"IsReachable = "& isReachable
);
</cfscript>
Apparently, google was unreachable. At least to java. Of course it is technically possible, yes. Probable ... no. Especially when a command line ping reported google was alive and kicking just moments prior to that.
After re-checking the API, I realized isReachable() might not be as good as it sounded. Aside from the usual disclaimers about firewalls and blocking, the API states:
A typical implementation will use ICMP ECHO REQUESTs if the privilege can be obtained, otherwise it will try to establish a TCP connection on port 7 (Echo) of the destination host.
Since I had no idea what a typical implementation was, I fired up Wireshark to see what was really happening. Sure enough, Wireshark showed isReachable() was using a TCP connection, not ICMP. Since TCP Echo is often disabled, that explained why isReachable() returned false.
So I thought to myself, either I do not have a typical implementation, or the API is wrong. (My money is on the latter). Originally I thought the jvm might be able to use ICMP through JNI perhaps. But apparently not. So back to the drawing board I went.
That is when I found .NET's simple Ping class. Its Send(..) method has four parameters: target host, timeout, sample data packet and options (time to live and discard fragmented packets). Host and options are complex objects. So you have to create an instance of those classes first. Once you have all of the necessary objects, simply call Send(..) to execute the ping and get the response.
<cfscript>
ping = createObject(".net", "System.Net.NetworkInformation.Ping");
dns = createObject(".net", "System.Net.Dns");
ips = dns.GetHostAddresses( "www.google.com" );
// arbitrary data to be transmitted
data = listToArray(repeatString("1,", 32));
// set the ttl (time to live) = 64 and disable fragmenting
options = createObject(".net", "System.Net.NetworkInformation.PingOptions").init(64, true);
reply = ping.Send ( ips[1], 100, javacast("short[]", data), options);
status = createObject(".net", "System.Net.NetworkInformation.IPStatus");
</cfscript>
Finally, check the response status to determine if the ping was successful. The example below displays all of the options used for debugging purposes. But all you really need to do is check the response status.
One oddity you may notice. For whatever reason, I do not believe you can access the class properties by name alone, as you can in .NET (or with java objects). So you must use the method reply.Get_Address() instead of the shorter form reply.Address.
<!--- using HR tags because of a blogger bug --->
<cfif reply.Get_Status() eq status.Success>
<cfoutput>
Get_Address = #reply.Get_Address().ToString()# <hr />
Get_RoundTripTime = #reply.Get_RoundtripTime().ToString()# <hr />
Get_Options.Ttl (Time to Live) = #reply.Get_Options().Get_Ttl()# <hr />
Get_Options.DontFragment = #reply.Get_Options().Get_DontFragment()# <hr />
Get_Buffer (Length) = #ArrayLen(reply.Get_Buffer())# <hr />
</cfoutput>
<cfelse>
Drat. Something went wrong ...
</cfif>
Anyway, I thought this was an interesting alternative to ping.exe. Plus, it was a good opportunity to brush up on my CF / .NET skills ;)
in my searches. Usually anything from cflib.org is pretty highly ranked.
Well, in any event, it was still a good learning experience about why not to use java for ping ;). http://www.cflib.org/udf/Ping
0 comments:
Post a Comment