/// <summary> /// This routine creates an instance of the Ipv4Header class from a byte /// array that is a received IGMP packet. This is useful when a packet /// is received from the network and the header object needs to be /// constructed from those values. /// </summary> /// <param name="ipv4Packet">Byte array containing the binary IPv4 header</param> /// <param name="bytesCopied">Number of bytes used in header</param> /// <returns>Returns the Ipv4Header object created from the byte array</returns> static public Ipv4Header Create(byte[] ipv4Packet, ref int bytesCopied) { Ipv4Header ipv4Header = new Ipv4Header(); // Make sure byte array is large enough to contain an IPv4 header if (ipv4Packet.Length < Ipv4Header.Ipv4HeaderLength) { return(null); } // Decode the data in the array back into the class properties ipv4Header.ipVersion = (byte)((ipv4Packet[0] >> 4) & 0xF); ipv4Header.ipLength = (byte)(ipv4Packet[0] & 0xF); ipv4Header.ipTypeOfService = ipv4Packet[1]; ipv4Header.ipTotalLength = BitConverter.ToUInt16(ipv4Packet, 2); ipv4Header.ipId = BitConverter.ToUInt16(ipv4Packet, 4); ipv4Header.ipOffset = BitConverter.ToUInt16(ipv4Packet, 6); ipv4Header.ipTtl = ipv4Packet[8]; ipv4Header.ipProtocol = ipv4Packet[9]; ipv4Header.ipChecksum = BitConverter.ToUInt16(ipv4Packet, 10); ipv4Header.ipSourceAddress = new IPAddress(BitConverter.ToUInt32(ipv4Packet, 12)); ipv4Header.ipDestinationAddress = new IPAddress(BitConverter.ToUInt32(ipv4Packet, 16)); bytesCopied = ipv4Header.Length; return(ipv4Header); }
/// <summary> /// This is the asynchronous callback that is fired when an async ReceiveFrom. /// An asynchronous ReceiveFrom is posted by calling BeginReceiveFrom. When this /// function is invoked, it calculates the elapsed time between when the ping /// packet was sent and when it was completed. /// </summary> /// <param name="ar">Asynchronous context for operation that completed</param> static void PingReceiveCallback(IAsyncResult ar) { RawSocketPing rawSock = (RawSocketPing)ar.AsyncState; TimeSpan elapsedTime; int bytesReceived = 0; ushort receivedId = 0; try { // Keep a count of how many async operations are outstanding -- one just completed // so decrement the count. Interlocked.Decrement(ref rawSock.pingOutstandingReceives); // If we're done because ping is exiting and the socket has been closed, // set the done event if (rawSock.pingSocket == null) { if (rawSock.pingOutstandingReceives == 0) { rawSock.pingDoneEvent.Set(); } return; } // Complete the receive op by calling EndReceiveFrom. This will return the number // of bytes received as well as the source address of who sent this packet. bytesReceived = rawSock.pingSocket.EndReceiveFrom(ar, ref rawSock.castResponseEndPoint); // Calculate the elapsed time from when the ping request was sent and a response was // received. elapsedTime = DateTime.Now - rawSock.pingSentTime; rawSock.responseEndPoint = (IPEndPoint)rawSock.castResponseEndPoint; // Here we unwrap the data received back into the respective protocol headers such // that we can find the ICMP ID in the ICMP or ICMPv6 packet to verify that // the echo response we received was really a response to our request. if (rawSock.pingSocket.AddressFamily == AddressFamily.InterNetwork) { Ipv4Header v4Header; IcmpHeader icmpv4Header; byte[] pktIcmp; int offset = 0; // Remember, raw IPv4 sockets will return the IPv4 header along with all // subsequent protocol headers v4Header = Ipv4Header.Create(rawSock.receiveBuffer, ref offset); pktIcmp = new byte[bytesReceived - offset]; Array.Copy(rawSock.receiveBuffer, offset, pktIcmp, 0, pktIcmp.Length); icmpv4Header = IcmpHeader.Create(pktIcmp, ref offset); /*Console.WriteLine("Icmp.Id = {0}; Icmp.Sequence = {1}", * * icmpv4Header.Id, * * icmpv4Header.Sequence * * );*/ receivedId = icmpv4Header.Id; } if (receivedId == rawSock.pingId) { string elapsedString; // Print out the usual statistics for ping if (elapsedTime.Milliseconds < 1) { elapsedString = "<1"; } else { elapsedString = "=" + elapsedTime.Milliseconds.ToString(); } } // Post another async receive if the count indicates for us to do so. if (rawSock.pingCount > 0) { rawSock.pingSocket.BeginReceiveFrom( rawSock.receiveBuffer, 0, rawSock.receiveBuffer.Length, SocketFlags.None, ref rawSock.castResponseEndPoint, rawSock.receiveCallback, rawSock ); // Keep track of outstanding async operations Interlocked.Increment(ref rawSock.pingOutstandingReceives); } else { // If we're done then set the done event if (rawSock.pingOutstandingReceives == 0) { rawSock.pingDoneEvent.Set(); } } // If this is indeed the response to our echo request then signal the main thread // that we received the response so it can send additional echo requests if // necessary. This is done after another async ReceiveFrom is already posted. if (receivedId == rawSock.pingId) { rawSock.pingReceiveEvent.Set(); } } catch (SocketException err) { Console.WriteLine("Socket error occurred in async callback: {0}", err.Message); } }