// Following code comes from Peter A. Bromberg, Ph.D.
// Please look at following URL in more detail.
// http://www.eggheadcafe.com/articles/20020209.asp
//
// Version 2.0 by Uchukamen.
// Changed PingHost to handle ref float deltaTime to get ping delta time.
// Changed Non blocking mode.
// All thanks should go to Peter and Lance Olson.
using System;
namespace Uchukamen.Util // change this to yourcompany.yourdivision.whatever
{
using System;
using System.Net;
using System.Net.Sockets;
/// <summary>
/// The Main Ping Class
/// </summary>
public class Ping
{
//Declare some Constant Variables
const int SOCKET_ERROR = -1;
const int ICMP_ECHO = 8;
/// <summary>
/// This public method takes the "hostname" of the server
/// and then it pings it and shows the response time
/// Data is returned as a string. IP addresses are resolved.
/// Example usage:
/// using .CBS.Util
/// Ping p = new Ping();
/// textBox2.Text = p.PingHost(textBox1.Text);
/// </summary>
public string PingHost(string host, out float deltaTime)
{
deltaTime = -1.0F;
//Declare the IPHostEntry
IPHostEntry serverHE, fromHE;
int nBytes = 0;
int dwStart = 0, dwStop = 0;
//Initialize a Socket of Type ICMP
Socket socket =
new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
// Get the server endpoint
try
{
serverHE = Dns.GetHostByName(host);
}
catch(Exception)
{
return "Host not found"; // uh-oh!
}
// Convert the server IP_EndPoint to an EndPoint
IPEndPoint ipepServer = new IPEndPoint(serverHE.AddressList[0], 0);
EndPoint epServer = (ipepServer);
// Set the receiving endpoint to the client machine
fromHE = Dns.GetHostByName(Dns.GetHostName());
IPEndPoint ipEndPointFrom = new IPEndPoint(fromHE.AddressList[0], 0);
EndPoint EndPointFrom = (ipEndPointFrom);
int PacketSize = 0;
IcmpPacket packet = new IcmpPacket(); // didn't know we had this in .Net, eh?
// (script kiddies: GET LOST!)
// Construct the packet to send
packet.Type = ICMP_ECHO; //8
packet.SubCode = 0;
packet.CheckSum = UInt16.Parse("0");
packet.Identifier = UInt16.Parse("45");
packet.SequenceNumber = UInt16.Parse("0");
int PingData = 32; // sizeof(IcmpPacket) - 8;
packet.Data = new Byte[PingData];
//Initialize the Packet.Data
for (int i = 0; i < PingData; i++)
{
packet.Data[i] = (byte)'#';
}
// Variable to hold the total Packet size
PacketSize = PingData + 8;
Byte [] icmp_pkt_buffer = new Byte[ PacketSize ];
Int32 Index = 0;
// Call Method Serialize which counts
// The total number of Bytes in the Packet
Index = Serialize(
packet,
icmp_pkt_buffer,
PacketSize,
PingData );
//Error in Packet Size
if( Index == -1 )
{
return "Error Creating Packet";
}
// convert into a UInt16 array
//Get the Half size of the Packet
Double double_length = Convert.ToDouble(Index);
Double dtemp = Math.Ceiling( double_length / 2);
int cksum_buffer_length = Convert.ToInt32(dtemp);
//Create a Byte Array
UInt16 [] cksum_buffer = new UInt16[cksum_buffer_length];
//Code to initialize the Uint16 array
int icmp_header_buffer_index = 0;
for( int i = 0; i < cksum_buffer_length; i++ )
{
cksum_buffer[i] =
BitConverter.ToUInt16(icmp_pkt_buffer,icmp_header_buffer_index);
icmp_header_buffer_index += 2;
}
//Call method to return a checksum
UInt16 u_cksum = checksum(cksum_buffer, cksum_buffer_length);
//Save checksum to Packet
packet.CheckSum = u_cksum;
// Now that we have the checksum, serialize the packet again
Byte [] sendbuf = new Byte[ PacketSize ];
//again check the packet size
Index = Serialize(
packet,
sendbuf,
PacketSize,
PingData );
//if there is an error return it
if( Index == -1 )
{
return "Error Creating Packet";
}
dwStart = System.Environment.TickCount; // Start timing
//send the Packet over the socket
if ((nBytes = socket.SendTo(sendbuf, PacketSize, 0, epServer)) == SOCKET_ERROR)
{
return "Socket Error: cannot send Packet";
}
// Initialize the buffers. The receive buffer is the size of the
// ICMP header plus the IP header (20 bytes)
Byte [] ReceiveBuffer = new Byte[256];
nBytes = 0;
// loop for checking the time of the server response
IAsyncResult ar = socket.BeginReceiveFrom(ReceiveBuffer, 0,
256, SocketFlags.None, ref EndPointFrom, null, null);
// Wait for 1000mSec
bool result = ar.AsyncWaitHandle.WaitOne(1000, false);
deltaTime = dwStop = System.Environment.TickCount - dwStart; // stop timing
string reply = null;
if (result)
{
// Successfully Received
nBytes = socket.EndReceiveFrom(ar, ref EndPointFrom);
reply = "Reply from "+ epServer.ToString()+" in " +
dwStop + "ms. Received: "+ nBytes + " Bytes.";
}
else
{
reply = "Timed out in " + dwStop + "ms.";
}
// Console.WriteLine(reply); // for debug
// close the socket
socket.Close();
return reply;
}
/// <summary>
/// This method get the Packet and calculates the total size
/// of the Pack by converting it to byte array
/// </summary>
public static Int32 Serialize(IcmpPacket packet, Byte[] Buffer,
Int32 PacketSize, Int32 PingData )
{
Int32 cbReturn = 0;
// serialize the struct into the array
int Index=0;
Byte [] b_type = new Byte[1];
b_type[0] = (packet.Type);
Byte [] b_code = new Byte[1];
b_code[0] = (packet.SubCode);
Byte [] b_cksum = BitConverter.GetBytes(packet.CheckSum);
Byte [] b_id = BitConverter.GetBytes(packet.Identifier);
Byte [] b_seq = BitConverter.GetBytes(packet.SequenceNumber);
Array.Copy( b_type, 0, Buffer, Index, b_type.Length );
Index += b_type.Length;
Array.Copy( b_code, 0, Buffer, Index, b_code.Length );
Index += b_code.Length;
Array.Copy( b_cksum, 0, Buffer, Index, b_cksum.Length );
Index += b_cksum.Length;
Array.Copy( b_id, 0, Buffer, Index, b_id.Length );
Index += b_id.Length;
Array.Copy( b_seq, 0, Buffer, Index, b_seq.Length );
Index += b_seq.Length;
// copy the data
Array.Copy( packet.Data, 0, Buffer, Index, PingData );
Index += PingData;
if( Index != PacketSize/* sizeof(IcmpPacket) */)
{
cbReturn = -1;
return cbReturn;
}
cbReturn = Index;
return cbReturn;
}
/// <summary>
/// This Method has the algorithm to make a checksum
/// </summary>
public static UInt16 checksum( UInt16[] buffer, int size )
{
Int32 cksum = 0;
int counter;
counter = 0;
while ( size > 0 )
{
UInt16 val = buffer[counter];
cksum += Convert.ToInt32( buffer[counter] );
counter += 1;
size -= 1;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (UInt16)(~cksum);
}
} // class ping
/// <summary>
/// Class that holds the Packet information
/// </summary>
public class IcmpPacket
{
public Byte Type; // type of message
public Byte SubCode; // type of sub code
public UInt16 CheckSum; // ones complement checksum of struct
public UInt16 Identifier; // identifier
public UInt16 SequenceNumber; // sequence number
public Byte [] Data;
} // class IcmpPacket
}
|