Other Posts in Networking

  1. TCP/IP vs. UDP
  2. Pinging Another Computer Using C#

Pinging Another Computer Using C#

10/29/2009

There are times when I need to know when a server goes down. Or sometimes I just want to know why the hell I can't read Saturday Morning Breakfast Cereal in the morning (or for that matter, XKCD). So a while ago I created a bit of code that would ping a server. By the way, when you ping another computer what you're really doing is using the echo function of the Internet Control Message Protocol. The nice thing about it is that it's extremely simple to implement.

   1: /// <summary>
   2: /// Class used to ping another computer
   3: /// </summary>
   4: public static class Ping
   5: {
   6:     #region Public Static Functions
   7:  
   8:     /// <summary>
   9:     /// Does a ping against the host specified
  10:     /// </summary>
  11:     /// <param name="Address">Address of the host</param>
  12:     /// <returns>True if a response is received, false otherwise</returns>
  13:     public static bool PingHost(string Address)
  14:     {
  15:         IPHostEntry Server, From;
  16:         Socket Socket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.Icmp);
  17:         Socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, 1000);
  18:         try
  19:         {
  20:             Server = Dns.GetHostEntry(Address);
  21:             From = Dns.GetHostEntry(Dns.GetHostName());
  22:         }
  23:         catch (Exception)
  24:         {
  25:             Socket.Close();
  26:             throw new Exception("Can't find host");
  27:         }
  28:  
  29:         EndPoint EndPoint = new IPEndPoint(Server.AddressList[0], 0);
  30:         EndPoint EndPointFrom = new IPEndPoint(From.AddressList[0], 0);
  31:  
  32:         int PacketSize = 40;
  33:         Packet Packet = new Packet();
  34:         Packet.Type = 8;
  35:         Packet.SubCode = 0;
  36:         Packet.Check = 0;
  37:         Packet.ID = 45;
  38:         Packet.SequenceNumber = 0;
  39:         int DataSize = 32;
  40:         Packet.Data = new byte[DataSize];
  41:         for (int x = 0; x < DataSize; ++x)
  42:         {
  43:             Packet.Data[x] = (byte)'#';
  44:         }
  45:         
  46:         byte[] Buffer = Serialize(PacketSize, Packet);
  47:         double CheckSumSize=System.Math.Ceiling((double)PacketSize/2);
  48:  
  49:         ushort []CheckSumBuffer=new ushort[(int)CheckSumSize];
  50:         
  51:         int BufferIndex=0;
  52:         for(int x=0;x<(int)CheckSumSize;++x)
  53:         {
  54:             CheckSumBuffer[x]=BitConverter.ToUInt16(Buffer,BufferIndex);
  55:             BufferIndex+=2;
  56:         }
  57:         Packet.Check = CheckSum(CheckSumBuffer);
  58:  
  59:         Buffer = Serialize(PacketSize, Packet);
  60:  
  61:         if (Socket.SendTo(Buffer, PacketSize, 0, EndPoint) == -1)
  62:         {
  63:             Socket.Close();
  64:             throw new Exception("Couldn't send packet");
  65:         }
  66:         Buffer=new byte[256];
  67:         int NumBytes = Socket.ReceiveFrom(Buffer, 256, SocketFlags.None, ref EndPointFrom);
  68:         if (NumBytes == -1)
  69:         {
  70:             Socket.Close();
  71:             throw new Exception("Host not responding");
  72:         }
  73:         else if (NumBytes > 0)
  74:         {
  75:             Socket.Close();
  76:             return true;
  77:         }
  78:  
  79:         Socket.Close();
  80:         return false;
  81:     }
  82:  
  83:     #endregion
  84:  
  85:     #region Private Static Functions
  86:  
  87:     /// <summary>
  88:     /// Does a check sum of an array
  89:     /// </summary>
  90:     /// <param name="CheckSumBuffer">Buffer to do a check sum on</param>
  91:     /// <returns>The check sum of the buffer</returns>
  92:     private static ushort CheckSum(ushort[] CheckSumBuffer)
  93:     {
  94:         Int32 Sum = 0;
  95:         for (int x = 0; x < CheckSumBuffer.Length; ++x)
  96:         {
  97:             Sum += Convert.ToInt32(CheckSumBuffer[x]);
  98:         }
  99:         Sum = (Sum >> 16) + (Sum & 0xffff);
 100:         Sum += (Sum >> 16);
 101:         return (UInt16)(~Sum);
 102:     }
 103:  
 104:     /// <summary>
 105:     /// Serializes the packet into an array
 106:     /// </summary>
 107:     /// <param name="PacketSize">Size of the packet</param>
 108:     /// <param name="Packet">Packet to serialize</param>
 109:     /// <returns>The packet in byte array form</returns>
 110:     private static byte[] Serialize(int PacketSize, Packet Packet)
 111:     {
 112:         byte[] Buffer = new byte[PacketSize];
 113:         int x = 2;
 114:         Buffer[0] = Packet.Type;
 115:         Buffer[1] = Packet.SubCode;
 116:  
 117:         byte[] TempArray = BitConverter.GetBytes(Packet.Check);
 118:         Array.Copy(TempArray, 0, Buffer, x, TempArray.Length);
 119:         x += TempArray.Length;
 120:  
 121:         TempArray = BitConverter.GetBytes(Packet.ID);
 122:         Array.Copy(TempArray, 0, Buffer, x, TempArray.Length);
 123:         x += TempArray.Length;
 124:  
 125:         TempArray = BitConverter.GetBytes(Packet.SequenceNumber);
 126:         Array.Copy(TempArray, 0, Buffer, x, TempArray.Length);
 127:         x += TempArray.Length;
 128:  
 129:         Array.Copy(Packet.Data, 0, Buffer, x, Packet.Data.Length);
 130:  
 131:         return Buffer;
 132:     }
 133:  
 134:     #endregion
 135:  
 136:     #region Private Classes
 137:  
 138:     /// <summary>
 139:     /// Acts as a packet holder
 140:     /// </summary>
 141:     private class Packet
 142:     {
 143:         public byte Type;
 144:         public byte SubCode;
 145:         public ushort Check;
 146:         public ushort ID;
 147:         public ushort SequenceNumber;
 148:         public byte[] Data;
 149:     }
 150:  
 151:     #endregion
 152: }

It's a decent amount of code but basically all you are doing is creating a Packet object and filling it out with basic information, the request type, sub code, ID, etc. Once that is done you serialize it into a byte array. You may be asking why I'm not using the .Net serialization. Well it doesn't quite work the way that you would expect, so it's just best to write another function to do it. After you serialize it, you need to do a check sum on it. Then store that in the packet and then finally serialize it again before sending it to the server. But after that you just wait for a response. If you get the response, yay it's up. Otherwise it's down (or not accepting pings which is a possibility). Anyway, that's it. Or of course you could just use the Ping class that Microsoft has built into .Net. You may be curious why I didn't mention it earlier. The Ping class wasn't added until 2.0 and my original code (although it's been updated) was created back in 1.1... Anyway, try it out, leave feedback, and happy coding.



Comments