//fill header into byte array
byte[] arHeader = header.toByteArray();
//create the array which is to be sent
byte[] arBytes = new byte[arHeader.Length + 32];
byte fill = Convert.ToByte('E'); //arbitrary fill data to be sent
for(int i = 0; i < arBytes.Length; i++)
{
arBytes[i] = fill;
}
//copy header to array which is to be sent
arHeader.CopyTo(arBytes, 0);
header.chksum = this.generateIPChecksum(arBytes);
//now this is goofy because after we inserted the checksum into
//the header we have to recreate the byte array
arHeader = header.toByteArray();
arHeader.CopyTo(arBytes, 0);
// Creates an IpEndPoint to capture the identity of the sending host.
IPEndPoint sender1 = new IPEndPoint(IPAddress.Any, 0);
EndPoint tempRemoteEP = (EndPoint)sender1;
// Creates a byte buffer to receive the message.
byte[] receiveBuffer = new byte[1024];
// Receives datagram from a remote host. This call blocks!
int nReceived = sock.ReceiveFrom(receiveBuffer, ref tempRemoteEP);
m_arTTL[m_idxPing] = receiveBuffer[8];
}
else
{
m_strErrorMessage = "Echoing socket is not readible in the given timeout";
}
//number of routing stations is part of the IP Header
//calculate elapsed time
DateTime now = DateTime.Now;
TimeSpan elapsedTime = new TimeSpan(now.Ticks - startTime.Ticks);
m_arTime[m_idxPing] = elapsedTime.Milliseconds;
return bResult;
}
private bool isIPAddress(string strAddress)
{
//return true if the address is an IP Address e.g. 192.168.8.111
//false points to a hostname like "INV111"
bool bResult = true;
private bool verifyReceivedMessage(byte[] arBytes, int nReceived, int minLengthSent)
{
//the first 4 bytes are the length of the IP Header in DWORDS
int nLengthIPHeader = arBytes[0] & 0x0f;
nLengthIPHeader *= 4; //in bytes
//enough data received
if(nLengthIPHeader + minLengthSent > nReceived)
{
m_strErrorMessage = "Not enough data echoed";
return false;
}
//check if it is an ICMP_ECHOREPLY packet
if(arBytes[nLengthIPHeader] != 0)
{
m_strErrorMessage = "Wrong type of telegram echoed";
return false;
}
int nId = arBytes[nLengthIPHeader + 6] + arBytes[nLengthIPHeader + 7] * 256;
//check echoed process id is ours
if(nId != Convert.ToUInt16(Process.GetCurrentProcess().Id)) //lossy conversion
{
m_strErrorMessage = "Received echoed data was not sent by this process";
return false;
}
return true;
}
private int calcAvgTime()
{
int result = 0;
foreach (int i in m_arTime)
{
result += i;
}
result /= m_arTime.Length;
return result;
}
private int calcAvgTTL()
{
int result = 0;
foreach (int i in m_arTTL)
{
//only count successful pings
if(m_arResults[i] == true)
{
result += i;
}
}
result /= m_arTTL.Length;
return result;
}
private void clearStats()
{
//clear statistical data
for(int i = 0; i < m_arTime.Length; i++)
{
m_arTime[i] = 0;
m_arTTL[i] = 0;
}
}
}
}
using System;
using System.Net;
using System.Diagnostics;
using System.Net.Sockets;
using System.Collections;
namespace cmpDWPing
{
///
//Implements an Ethernet Ping component
//Ping is part of the ICMP (Internet Control Message Protocol) which serves
//Hosts and Routers for the purpose of error messaging and exchanging status and commands.
//It is part of the IP protocol and therefore cannot be considered as reliable.
//The following ICMP messages are used here to implement a ping functionality:
//Echo Request
//Echo Answer
//The interface is pretty straightforward:
//the ping method performs the network ping and returns success or failure
//in case of failure ask the ErrorMessage property for the reason
//
// There are some properties which you can use for setting and getting information. See the interface below
//
//
//
//
//You can use this component as a COM object if
//you create a COM callable wrapper (CCW) by the following command line programs:
//the typelib is created by the project setting "register for COM interop":
//regasm bin/debug/cmpDWPing.dll
//if you also want to manually create a typelib use the following line
//regasm /tlb:cmpDWPing.tlb bin/debug/cmpDWPing.dll
//use the following lines to register the component in the global assembly cache
//gacutil /u cmpDWPing
//gacutil /i bin/debug/cmpDWPing.dll
//
//Beforehand justification: Because of the C-style design of the ICMP protocol data structures
//which are meant to be cast this way and that and therefore not very
//suitable to a strict language like C#, we have to
//adopt some pretty awkward code here.
///
interface IDWPing
{
short ping(string strHostName); // 1 = success, 0 = failure
int Timeout {set;} //default = 500msec
int Repeats {set;} //default = 0
int AvgTime {get;} //measured average response time
int AvgTTL {get;} //measured average number of routing nodes the ping traveled
string ErrorMessage {get;} //a verbose error message in case of failure
}
struct ICMPHeader
{
public byte type;
public byte code;
public ushort chksum;
public ushort id;
public ushort seq;
public ulong timestamp;
public int Timeout { set{ m_Timeout = MinMax.max(value, 1); }}
public int Repeats { set
{ int n = MinMax.max(value, 1);
m_arTime = new int[n];
m_arTTL = new byte[n];
m_arResults = new bool[n];
}
}
public int AvgTime { get{ return this.calcAvgTime(); }}
public int AvgTTL { get{ return this.calcAvgTTL(); }}
public string ErrorMessage { get{ return m_strErrorMessage; }}
public CDWPing()
{
m_arTime = new int[1]; //size of m_arTime is number of tries
m_arTTL = new Byte[1];
m_arResults = new bool[1];
m_strErrorMessage = "Don't know what happened";
m_Timeout = 500; //msec
}
public short ping(string strHostName)
{
m_strErrorMessage = "No error occured";
this.clearStats();
short result = 0;
//convert strHostName to an IPEndPoint
try
{
IPEndPoint lep;
//check if strHostname is already a dotted address
//and create an IPEndpoint from it
//note: port 7 is for echo but is irrelevant because of the socket type we are going to use
const int echoPort = 7;