Implementing PING Without Using Raw Sockets

Internet PINGs Using Delphi and Icmp.dll

Man using laptop at home
deimagine/E+/Getty Images

Windows supports an Internet Control Message Protocol (ICMP) to determine whether or not a particular host is available. ICMP is a network layer protocol that delivers flow control, error messages, routing, and other data between Internet hosts. ICMP is primarily used by application developers for a network ping.

What Is a Ping?

A ping is the process of sending an echo message to an IP address and reading the reply to verify a connection between TCP/IP hosts. If you are writing a new application, you will be better to use the Winsock 2 raw sockets support, implemented in Indy, for example.

Please note, however, that for Windows NT and Windows 2000 implementations, Raw Sockets are subject to security checks and are accessible only to members of the administrator's group. Icmp.dll provides functionality that allows developers to write Internet ping applications on Windows systems without Winsock 2 support. 

Note that the Winsock 1.1 WSAStartup function must be called prior to using the functions exposed by ICMP.DLL. If you do not do this, the first call to IcmpSendEcho will fail with error 10091 (WSASYSNOTREADY).

Below you can find the Ping unit's source code. Here are two examples of usage.

Example 1: Code Snippet

uses Ping;...​
const
ADP_IP = '208.185.127.40'; (* http://delphi.about.com *)
beginIf
Ping.Ping(ADP_IP) then ShowMessage('About Delphi Programming reachable!');
end
;

Example 2: Console Mode Delphi Program

Our next example is a console mode Delphi program that uses the Ping unit: . Here's the Ping unit's source:

unit Ping;​
interfaceuses

Windows, SysUtils, Classes;
type

TSunB = packed record
s_b1, s_b2, s_b3, s_b4: byte;
end
;
TSunW = packed record
s_w1, s_w2: word;
end
;
PIPAddr = ^TIPAddr;
TIPAddr = record
case
integer of
0: (S_un_b: TSunB);1: (S_un_w: TSunW);2: (S_addr: longword);
end
;IPAddr = TIPAddr;
function
IcmpCreateFile : THandle; stdcall; external 'icmp.dll';
function
IcmpCloseHandle (icmpHandle : THandle) : boolean;
stdcall
; external 'icmp.dll'
function
IcmpSendEcho
(IcmpHandle : THandle; DestinationAddress : IPAddr;
RequestData : Pointer; RequestSize : Smallint;
RequestOptions : pointer;
ReplyBuffer : Pointer;
ReplySize : DWORD;
Timeout : DWORD) : DWORD; stdcall; external 'icmp.dll';
function
Ping(InetAddress : string) : boolean;
implementationuses

WinSock;
function
Fetch(var AInput: string;
const
ADelim: string = ' ';
const
ADelete: Boolean = true)
: string;
var

iPos: Integer;
begin
if
ADelim = #0 then begin
// AnsiPos does not work with #0

iPos := Pos(ADelim, AInput);
end else begin

iPos := Pos(ADelim, AInput);
end
;
if
iPos = 0 then begin
Result := AInput;
if
ADelete then begin
AInput := '';
end
;
end else begin

result := Copy(AInput, 1, iPos - 1);
if
ADelete then begin
Delete(AInput, 1, iPos + Length(ADelim) - 1);
end
;
end
;
end
;
procedure
TranslateStringToTInAddr(AIP: string; var AInAddr);
var

phe: PHostEnt;pac: PChar;GInitData: TWSAData;
begin

WSAStartup($101, GInitData);
try

phe := GetHostByName(PChar(AIP));
if
Assigned(phe) thenbegin
pac := phe^.h_addr_list^;
if
Assigned(pac) then
begin
with
TIPAddr(AInAddr).S_un_b do begin
s_b1 := Byte(pac[0]);s_b2 := Byte(pac[1]);s_b3 := Byte(pac[2]);s_b4 := Byte(pac[3]);
end
;
end
else
begin
raise
Exception.Create('Error getting IP from HostName');
end
;
end
else
begin
raise
Exception.Create('Error getting HostName');
end
;
except

FillChar(AInAddr, SizeOf(AInAddr), #0);
end
;WSACleanup;
end
;
function
Ping(InetAddress : string) : boolean;
var

Handle : THandle;
InAddr : IPAddr;
DW : DWORD;
rep : array[1..128] of byte;
begin

result := false;Handle := IcmpCreateFile;
if
Handle = INVALID_HANDLE_VALUE then
Exit;
TranslateStringToTInAddr(InetAddress, InAddr);
DW := IcmpSendEcho(Handle, InAddr, nil, 0, nil, @rep, 128, 0);Result := (DW 0);IcmpCloseHandle(Handle);
end
;​
end
.