ICMPSocket for REALbasic
by Charlie Boisseau & Aaron Ballman
February 2005


About these classes.
The ICMPSocket are used to send and receive ICMP (Internet Control Message Protocol) messages within REALbasic applications. Typically, ICMP is used for Ping and Traceroute implementations, although many other uses exist and should be achievable with these classes.

Requirements
These classes are currently supported on Mac OS X and Windows. Hopefully with a little more work they'll work on Linux too. Mac OS X Note: These classes use declares to the system's Mach-O libraries and therefore must be compiled as Mach-O. Compile them in a PEF application will fail.

If you use these classes in your project, be sure to let me know, and give Aaron and I credit in your about box.



Class ICMPSocket
Attributes:
  BytesAvailable As Integer (read only)
    The number of bytes waiting on the socket to be read. Calling Poll will read these to the internal receive buffer.
  TimeToLive As Integer (write only)
    The number of routers (or hops) the packets will pass before expiring and returning. Each router that the packet travels through decrements the TimeToLive (TTL) by one. When a packet's TTL is reduced to 0, it has expired and will be returned in the form of a ICMP_TIMXCEED packet.
  Handle As Integer
    The descriptor of the raw socket used for sending and receiving packets. This can be used with declares to provide additional functionality to the class.
Functions:
  Poll ()
    This function polls the socket for new data and fires the DataAvailable event if there are packets waiting. It also sends any packets waiting on the internal send buffer.
Note: Poll should be called at least once at the beginning of your ICMP operations.
  Close ()
    Stops the polling loop. This function should be called when your ICMP operations are complete.
  Write (Packet As ICMPPacket)
    Sends the passed ICMPPacket to the socket.
  Read () As ICMPPacket
    This function should be called in the DataAvailable event. It reads the first packet from the internal receive buffer and returns it. If there is likely to be more than one packet, use ReadAll.
  ReadAll () As ICMPPacket()
    Returns an array of ICMPPackets. This array will contain all packets waiting to be received on the internal receive buffer.
Events:
  DataAvailavble ()
    This event fires whenever there is data waiting to be read on the internal receive buffer.
  Error (As Integer)
    Any error the ICMPSocket will be reported using this event. Standard SocketCore error codes and error constants apply.

Class ICMPPacket
Attributes:
  Address As String
    The IP address or DNS name of the remote device to send to or has received this packet.
  Type As Integer
    The ICMP type code. This determines the sort of ICMP message you are sending or receiving. The following packet types are supported in this distribution:
  SubCode As Integer
    Determines other properties within specific ICMP message types. These are defined as constants in each individual ICMPPacket message type.
  Checksum As Integer
    This is used to determine whether the packet was successfully received. It is comprised of the binary one's compliment to the rest of the packet. Use the CalculateChecksum method to set this value for outgoing packets.
  Data As MemoryBlock
    This property is the actual storage location of all the values in each packet. It can be used for direct access to the values in the packet.
  ExtraData([offset As Integer]) As Memoryblock
    This property is used for accessing/writing data outwith the scope of the packet's parameters. For example, an ICMP_ECHO packet may have an additional payload beyond the Identifier and SequenceNumber. The optional parameter 'offset' can specify the location in the data to begin reading.
Functions:
  CalculateChecksum()
    This method calculates the checksum and attaches it to the packet. This should be called before an outgoing packet is sent.
  CalculateChecksum() As Integer
    Again, calculates the checksum for a packet and returns it. This can be used to calculate the checksum of an incoming packet, ensuring that it matches the packet's original checksum. If the two do not match, there may be an error in the packet.
  Resize()
    Removes any extra data from the end of the packet by resizing the 'Data' MemoryBlock to the location of the last-used byte. This should be called before sending a packet to prevent sending the unused data at the end of the packet. If this function isn't called, the packet will take longer to send.
  TypeCast() As ICMPPacket
    Checks the ICMP packet type and casts it as the relevant ICMPPacket message type. This function is used internally to provide the correct type of subclass in the ICMP read routines and to retrieve ICMPPacket data from ICMP_TIMXCEED and ICMP_PARAMPROB packets.

Class ICMP_ECHOREPLY ICMP_TYPE = 0

Super: ICMPPacket

This type of packet is a reply to an ICMP_ECHO request. It should contain the exact data sent in the original request. These packets are most often used in 'ping' and simple 'traceroute' implementations.

Attributes:
  Identifier As Integer
    This is a unique number identifying the source process of the packet. This allows many different ICMP_ECHO packets to be sent from different processes on the same machine without them getting confused. A common number to use is the application PID (Process ID). If your application is likely to use these packets in more than one place, you should use a more specific ID. For example the containing window's 'Handle' property.
  SequenceNumber As Integer
    In many cases, ICMP_ECHO packets are sent progressively over a period of time to check time delays. The SequenceNumber property is used to determine what order the packets were sent. This can also be used as a kind of sub-identifer. It doesn't strictly have to be used to send a sequence number.
  ExtraData As MemoryBlock
    This attribute references the remaining section of the packet, where any other data may be stored. For example, in 'ping' and 'traceroute' implementations, a timestamp may be added here to allow time delays to be calculated.

Class ICMP_UNREACH ICMP_TYPE = 3

Super: ICMPPacket

This message is generated by a router to inform the source host that the destination address is unreachable. This message is not generated in response to a datagram destined for a multicast address.

The IP header plus the first 8 bytes of the original datagram's data is returned to the sender. This data is used by the host to match the message to the appropriate process. If a higher level protocol uses port numbers, they are assumed to be in the first 64 data bits of the original datagram's data.

Attributes:
  NextHopMTU As Identifier
    From RFC 1191: For use when the [SubCode] is set to 4: when a router is unable to forward a datagram because it exceeds the MTU of the next-hop network and its 'Don't Fragment' bit is set, the router is required to return an ICMP Destination Unreachable message to the source of the datagram, with the Code indicating "fragmentation needed and DF set". To support the Path MTU Discovery technique specified in this memo, the router MUST include the MTU of that next-hop network in [AltNextHopMTU]. [NextHopMTU] remains unused, and MUST be set to zero.
  AltNextHopMTU As Integer
    As described above, this is provided when needed for the 'Path MTU Discovery' technique.
ExtraData As MemoryBlock
Here you can directly access the returned IP packet as a MemoryBlock. If the packet is an ICMP packet, use the 'OriginalICMPPacket' function to retrieve it as a native object.
Functions:
  OriginalICMPPacket() As ICMPPacket
   

With some ICMP packets, where errors have occurred, the IP header and first 8 bytes of the offending packet are returned. This function assumes the offending packet was an ICMP packet and returns a ICMPPacket object containing the data. This ICMPPacket is cast as its respective packet class. If the packet wasn't an ICMP packet, this function will return nil.

Note: Because only the first 8 bytes of the ICMP header are returned (4 bytes of which is the type, code and checksum), the returned object will most likely be incomplete. Generally, only enough information to identify the original packet is provided.

SubCode Constants :
  ICMP_UNREACH_NET = 0
    Network unreachable error.
  ICMP_UNREACH_HOST = 1
    Host unreachable error.
  ICMP_UNREACH_PROTOCOL = 2
    Protocol unreachable error. When the designated transport protocol is not supported.
  ICMP_UNREACH_PORT = 3
    Port unreachable error. When the designated transport protocol (e.g., UDP) is unable to demultiplex the datagram but has no protocol mechanism to inform the sender.
  ICMP_UNREACH_NEEDFRAG = 4
    The datagram is too big. Packet fragmentation is required but the DF bit in the IP header is set.
  ICMP_UNREACH_SRCFAIL = 5
    Source route failed error.
  ICMP_UNREACH_NET_UNKNOWN = 6
    Destination network unknown error.
  ICMP_UNREACH_HOST_UNKNOWN = 7
    Destination host unknown error.
  ICMP_UNREACH_ISOLATED = 8
    Source host isolated error. Obsolete.
  ICMP_UNREACH_NET_PROHIB = 9
    The destination network is administratively prohibited.
  ICMP_UNREACH_HOST_PROHIB = 10
    The destination host is administratively prohibited.
  ICMP_UNREACH_TOSNET = 11
    The network is unreachable for Type Of Service.
  ICMP_UNREACH_TOSHOST = 12
    The host is unreachable for Type Of Service.
  ICMP_UNREACH_FILTER_PROHIB = 13
    Communication Administratively Prohibited. This is generated if a router cannot forward a packet due to administrative filtering.
  ICMP_UNREACH_HOST_PRECEDENCE = 14
    Host precedence violation. Sent by the first hop router to a host to indicate that a requested precedence is not permitted for the particular combination of source/destination host or network, upper layer protocol, and source/destination port.
  ICMP_UNREACH_PRECEDENCE_CUTOFF = 15
    Precedence cutoff in effect. The network operators have imposed a minimum level of precedence required for operation; the datagram was sent with a precedence below this level.

Class ICMP_SOURCEQUENCH ICMP_TYPE = 4

Super: ICMPPacket

This message is a request to decrease the traffic rate of data messages sent to an internet destination. The offending packet is contained. NB: If it was an ICMP packet, retrieve it with OriginalICMPPacket.

Attributes:
ExtraData As MemoryBlock
Here you can directly access the returned IP packet as a MemoryBlock. If the packet is an ICMP packet, use the 'OriginalICMPPacket' function to retrieve it as a native object.
Functions:
  OriginalICMPPacket() As ICMPPacket
   

With some ICMP packets, where errors have occurred, the IP header and first 8 bytes of the offending packet are returned. This function assumes the offending packet was an ICMP packet and returns a ICMPPacket object containing the data. This ICMPPacket is cast as its respective packet class. If the packet wasn't an ICMP packet, this function will return nil.

Note: Because only the first 8 bytes of the ICMP header are returned (4 bytes of which is the type, code and checksum), the returned object will most likely be incomplete. Generally, only enough information to identify the original packet is provided.


Class ICMP_REDIRECT ICMP_TYPE = 5

Super: ICMPPacket

Contains a redirect message to send data packets on an alternative route. ICMP Redirect is a mechanism for routers to convey routing information to hosts.

Attributes:
IPAddress As String
The IP address of the gateway to redirect packets.
ExtraData As MemoryBlock
Here you can directly access the returned IP packet as a MemoryBlock. If the packet is an ICMP packet, use the 'OriginalICMPPacket' function to retrieve it as a native object.
Functions:
  OriginalICMPPacket() As ICMPPacket
   

With some ICMP packets, where errors have occurred, the IP header and first 8 bytes of the offending packet are returned. This function assumes the offending packet was an ICMP packet and returns a ICMPPacket object containing the data. This ICMPPacket is cast as its respective packet class. If the packet wasn't an ICMP packet, this function will return nil.

Note: Because only the first 8 bytes of the ICMP header are returned (4 bytes of which is the type, code and checksum), the returned object will most likely be incomplete. Generally, only enough information to identify the original packet is provided.

SubCode Constants :
  ICMP_REDIRECT_NET = 0
    Redirect for network error.
  ICMP_REDIRECT_HOST = 1
    Redirect for host error.
  ICMP_REDIRECT_TOSNET = 2
    Redirect for TOS and network error.
  ICMP_UNREACH_PORTREDIRECT_TOSHOST = 3
    Redirect for TOS and host error.

Class ICMP_ECHO ICMP_TYPE = 8

Super: ICMPPacket

This type of packet is a request for an ICMP_ECHOREPLY request packet to be sent back. It should contain the exact data sent in the original request. These packets are most often used in 'ping' and simple 'traceroute' implementations.

Attributes:
  Identifier As Integer
    This is a unique number identifying the source process of the packet. This allows many different ICMP_ECHO packets to be sent from different processes on the same machine without them getting confused. A common number to use is the application PID (Process ID). If your application is likely to use these packets in more than one place, you should use a more specific ID. For example, the containing window's 'Handle' property.
  SequenceNumber As Integer
    In many cases ICMP_ECHO packets are sent progressively over a period of time to check time delays. The SequenceNumber property is used to determine the order the packets were sent. This can also be used as a kind of sub-identifer. It doesn't strictly have to be used to send a sequence number.
  ExtraData As MemoryBlock
    This attribute references the remaining section of the packet, where any other data may be stored. For example in 'ping' and 'traceroute' implementations, a timestamp may be added here to allow tine delays to be calculated.


Class ICMP_ROUTERADVERT ICMP_TYPE = 9

Super: ICMPPacket

The ICMP router discovery messages are called "Router Advertisements" and "Router Solicitations". Each router periodically multicasts a Router Advertisement from each of its multicast interfaces, announcing the IP address(es) of that interface. Hosts discover the addresses of their neighbouring routers simply by listening for advertisements.

Attributes:
  AdvertCount As Integer
    The number of router advertisements in the message. Each advertisement contains one router address/preference level pair.
  AddressEntrySize As Integer
    The number of 32-bit words of information for each router address entry in the list. The value is normally set to 2 (router address + preference level).
  Lifetime As Integer
    The maximum number of seconds that the router addresses in this list may be considered valid.
  RouterAddress(Index As Integer) As ICMP_RouterAddress
    Used to access the router address and preference (contained in the ICMP_RouterAddress class) of the index specified. If the specified index isn't valid, an OutOfBoundsException will be raised.

Class ICMP_RouterAddress

Used by the ICMP_ROUTERADVERT messages to contain information on each router advertisement.

Attributes:
  Address As String
    The IP address of the router's advertised interface.
  Preference As Integer
    The preferability of the router address as a default router address, relative to other router addresses on the same subnet. This is a signed, twos-complement value where higher values indicate that the route is more preferable.

Class ICMP_ROUTERSOLICIT ICMP_TYPE = 10

Super: ICMPPacket

When a host attached to a multicast link starts up, it may multicast a Router Solicitation to ask for immediate advertisements, rather than waiting for the next periodic ones to arrive. If (and only if) no advertisements are forthcoming, the host may retransmit the solicitation a small number of times, but then must desist from sending any more solicitations.

There are no additional attributes, functions or constants for this class.


Class ICMP_TIMXCEED ICMP_TYPE = 11

Super: ICMPPacket

A host may receive an ICMP Time Exceeded Message from a destination host that has timed out and discarded an incomplete datagram.

Attributes:
ExtraData As MemoryBlock
Here you can directly access the returned IP packet as a MemoryBlock. If the packet is an ICMP packet, use the 'OriginalICMPPacket' function to retrieve it as a native object.
Functions:
  OriginalICMPPacket() As ICMPPacket
   

With some ICMP packets, where errors have occurred, the IP header and first 8 bytes of the offending packet are returned. This function assumes the offending packet was an ICMP packet and returns an ICMPPacket object containing the data. This ICMPPacket is cast as its respective packet class. If the packet wasn't an ICMP packet, this function will return nil.

Note: Because only the first 8 bytes of the ICMP header are returned (4 bytes of which is the type, code and checksum), the returned object will most likely be incomplete. Generally, only enough information to identify the original packet is provided.

SubCode Constants :
  ICMP_TIMXCEED_INTRANS = 0
    Time To Live (TTL) reached 0 during transit.
  ICMP_TIMXCEED_REASS = 1
    Fragment reassembly timeout.

Class ICMP_PARAMPROB ICMP_TYPE = 12

Super: ICMPPacket

This message is generated as a response for any error not specifically covered by another ICMP message.

Attributes:
ErrorOffset As Integer
Specifies where in the returned packet (accessible directly using ExtraData) the error has occurred.
ExtraData As MemoryBlock
Here you can directly access the returned IP packet as a MemoryBlock. If the packet is an ICMP packet, use the 'OriginalICMPPacket' function to retrieve it as a native object.
Functions:
  OriginalICMPPacket() As ICMPPacket
   

With some ICMP packets, where errors have occurred, the IP header and first 8 bytes of the offending packet are returned. This function assumes the offending packet was an ICMP packet and returns an ICMPPacket object containing the data. This ICMPPacket is cast as its respective packet class. If the packet wasn't an ICMP packet, this function will return nil.

Note: Because only the first 8 bytes of the ICMP header are returned (4 bytes of which is the type, code and checksum), the returned object will most likely be incomplete. Generally, only enough information to identify the original packet is provided.

SubCode Constants :
  ICMP_PARAMPROB_ERRATPTR = 0
    The IP header is invalid.
  ICMP_PARAMPROB_OPTABSENT = 1
    A required option is missing.

Class ICMP_TSTAMP ICMP_TYPE = 13
Class ICMP_TSTAMPREPLY ICMP_TYPE = 14

Super: ICMPPacket

The data received (a timestamp) in this message is returned in the reply together with an additional timestamp. The timestamp is an Integer containging the number of milliseconds since midnight UT.

Attributes:
  Identifier As Integer
    Used to help match timestamp requests to the associated reply. It may be set to zero.
  SequenceNumber As Integer
    Used to help match timestamp requests to the associated reply. It may be set to zero.
  OriginateTimestamp As Integer
    The time the sender last touched the message before sending it.
  RecieveTimestamp As Integer
    The time the echoer first touched the message on receipt.
  TransmitTimestamp As Integer
    The time the echoer last touched the message on sending it.

Class ICMP_IREQ ICMP_TYPE = 15
Class ICMP_IREQREPLY ICMP_TYPE = 16

Super: ICMPPacket

This message may be sent with the source network in the IP header source and destination address fields zero (which means "this" network). The replying IP module should send the reply with the addresses fully specified. This message is a way for a host to find out the number of the network it is on.

Attributes:
  Identifier As Integer
    Used to help match timestamp requests to the associated reply. It may be set to zero.
  SequenceNumber As Integer
    Used to help match timestamp requests to the associated reply. It may be set to zero.

Class ICMP_MASKREQ ICMP_TYPE = 17
Class ICMP_MASKREPLY ICMP_TYPE = 18

Super: ICMPPacket

A gateway receiving an address mask request should return it with the address mask field set to the 32-bit mask of the bits identifying the subnet and network, on which the request was received.

If the requesting host does not know its own IP address, it may leave the source field zero; the reply should then be broadcast. However, this approach should be avoided if at all possible, since it increases the superfluous broadcast load on the network. Even when the replies are broadcast, since there is only one possible address mask for a subnet, there is no need to match requests with replies. The "Identifier" and "Sequence Number" fields can be ignored.

Attributes:
  Identifier As Integer
    Used to help match timestamp requests to the associated reply. It may be set to zero.
  SequenceNumber As Integer
    Used to help match timestamp requests to the associated reply. It may be set to zero.
  AddressMask As String
    The subnet mask of the requesting host.