///
/// The main entry point for the application.
///
[STAThread]
static void Main(string[] args)
{
int timeToReplyMs = Ping("andrewbaker.ninja", 10000);
Console.WriteLine("Time Taken(ms): " + timeToReplyMs);
}
#region Ping Method
///
/// Pings a host and returns the time taken for the host to respond (given the host name or IP address of the host to ping).
///
/// The host (machine name or IP address) to ping.
/// The ping timeout in ms (zero represents infinite).
/// Returns the time in milliseconds to receive a response from the host.
public static int Ping(string host, int timeout)
{
//IPHostEntry ipHost = Dns.GetHostByName(host);
IPHostEntry ipHost = Dns.GetHostEntry(host);
// Ping the server
return Ping(ipHost, timeout);
}
///
/// Pings a host and returns the time taken for the host to respond.
///
/// The host to ping.
/// The ping timeout in ms (zero represents infinite).
/// Returns the time in milliseconds to receive a response from the host.
public static int Ping(IPHostEntry host, int timeout)
{
// Declare some Constant Variables
const int SOCKET_ERROR = -1;
const int ICMP_ECHO = 8;
int timeTaken;
// Declare the IPHostEntry
if (host == null)
{
throw new ArgumentNullException("host", "The host to ping must be specified.");
}
Socket socket = null;
try
{
// Initilize a Socket of the Type ICMP
socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
// Convert to the first Ip address from the host to an endpoint
IPEndPoint ipepServer = new IPEndPoint(_GetValidAddress(host.AddressList), 0);
EndPoint epServer = (ipepServer);
// Set the receiving endpoint to the client machine
IPHostEntry localHost;
localHost = Dns.GetHostEntry(Dns.GetHostName());
IPEndPoint ipEndPointFrom = new IPEndPoint(_GetValidAddress(localHost.AddressList), 0);
EndPoint EndPointFrom = (ipEndPointFrom);
int packetSize;
IcmpPacket packet = new IcmpPacket();
// Construct the echo packet
packet.Type = ICMP_ECHO; //8
packet.SubCode = 0;
packet.CheckSum = UInt16.Parse("0");
packet.Identifier = UInt16.Parse("45");
packet.SequenceNumber = UInt16.Parse("0");
int pingDataSize = 32; // sizeof(IcmpPacket) - 8;
packet.Data = new Byte[pingDataSize];
// Initilize the Packet.Data
for (int i = 0; i < pingDataSize; i++)
{
packet.Data[i] = (byte)'#';
}
// Variable to hold the total Packet size
packetSize = pingDataSize + 8;
Byte[] icmpPacketBuffer = new Byte[packetSize];
int totalPacketSize;
// Call Serialize, which counts the total number of Bytes in the Packet
totalPacketSize = _SerializePacket(packet, icmpPacketBuffer, packetSize, pingDataSize);
// Error in Packet Size
if (totalPacketSize == -1)
{
// Throw serialization exception
throw new ApplicationException("Error serializing packet buffer");
}
// Get the packet into a UInt16 array
// Get the Half size of the Packet
Double packetSizeDouble = Convert.ToDouble(totalPacketSize);
Double halfPacketSizeDouble = Math.Ceiling(packetSizeDouble / 2);
int checkSumBufferLength = Convert.ToInt32(halfPacketSizeDouble);
// Create a Byte Array
UInt16[] checkSumBuffer = new UInt16[checkSumBufferLength];
// Code to initilize the Uint16 array
int icmpHeaderBufferIndex = 0;
for (int i = 0; i < checkSumBufferLength; i++)
{
checkSumBuffer[i] = BitConverter.ToUInt16(icmpPacketBuffer, icmpHeaderBufferIndex);
icmpHeaderBufferIndex += 2;
}
// Call a method which will return a checksum
UInt16 unsignedCheckSum = _CalcChecksum(checkSumBuffer, checkSumBufferLength);
// Save the checksum to the Packet
packet.CheckSum = unsignedCheckSum;
// Have the checksum, serialize the packet again
Byte[] sendbuf = new Byte[packetSize];
// Check the packet size
totalPacketSize = _SerializePacket(packet, sendbuf, packetSize, pingDataSize);
if (totalPacketSize == -1)
{
// Throw serialization exception
throw new ApplicationException("Error serializing packet buffer");
}
// Start timing
int dwStart = Environment.TickCount;
// Send the Packet
if (socket.SendTo(sendbuf, packetSize, 0, epServer) == SOCKET_ERROR)
{
throw new ApplicationException("Failed to send packet to " + host.HostName + ".");
}
// Initialize the buffers. The receive buffer is the size of the
// ICMP header plus the IP header (20 bytes)
Byte[] arrayBytesReceived = new Byte[256];
// Loop for checking the time of the server responding
while (true)
{
int nBytes = socket.ReceiveFrom(arrayBytesReceived, 256, 0, ref EndPointFrom);
timeTaken = Environment.TickCount - dwStart;
if (nBytes == SOCKET_ERROR)
{
throw new ApplicationException("Failed to receive response to echo packet from " + host.HostName + ".");
}
else if (nBytes > 0)
{
// Received message
// int dwStop = Environment.TickCount - dwStart;
// Console.WriteLine("Reply from " + epServer.ToString() + " in " + dwStop + "MS :Bytes Received" + nBytes);
break;
}
// Default to a one second timeout
if (timeTaken > timeout && timeout > 0)
{
throw new ApplicationException("Ping to " + host.HostName + " timed out after " + timeout + " milliseconds.");
}
}
}
finally
{
if (socket != null)
{
// close the socket
socket.Shutdown(SocketShutdown.Both);
socket.Close();
}
}
return timeTaken;
}
//
// Find a valid IP address
private static IPAddress _GetValidAddress(IPAddress[] addressList)
{
for (int i = 0; i < addressList.Length; i++)
{
try
{
var address = addressList[i].Address;
}
catch (Exception)
{
// Invalid address
continue;
}
// The address is valid
return addressList[i];
}
return null;
}
#region Private Methods
///
/// This method get the Packet and calculates the total size
/// of the Pack by converting it to byte array
///
private static int _SerializePacket(IcmpPacket packet, Byte[] Buffer, int PacketSize, int PingData)
{
int cbReturn;
// 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);
// Console.WriteLine("Serialize type ");
Array.Copy(b_type, 0, Buffer, Index, b_type.Length);
Index += b_type.Length;
// Console.WriteLine("Serialize code ");
Array.Copy(b_code, 0, Buffer, Index, b_code.Length);
Index += b_code.Length;
// Console.WriteLine("Serialize cksum ");
Array.Copy(b_cksum, 0, Buffer, Index, b_cksum.Length);
Index += b_cksum.Length;
// Console.WriteLine("Serialize id ");
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;
}
///
/// This Method has the algorithm to make a checksum
///
private static UInt16 _CalcChecksum(UInt16[] buffer, int size)
{
int cksum = 0;
int counter;
counter = 0;
while (size > 0)
{
UInt16 val = buffer[counter];
cksum += Convert.ToInt32(val);
counter += 1;
size -= 1;
}
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >> 16);
return (UInt16)(~cksum);
}
#endregion Private Methods
#region IcmpPacket Class (Private)
///
/// Class that holds the Pack information.
///
private class IcmpPacket
{
///
/// Type of message
///
public Byte Type;
///
/// Type of sub code
///
public Byte SubCode;
///
/// Complement checksum of struct
///
public UInt16 CheckSum;
///
/// Identifier
///
public UInt16 Identifier;
///
/// Sequence number
///
public UInt16 SequenceNumber;
///
/// The data
///
public Byte[] Data;
}
#endregion IcmpPacket Class (Private)
}