| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709 |
- {==============================================================================|
- | Project : Ararat Synapse | 004.000.000 |
- |==============================================================================|
- | Content: PING sender |
- |==============================================================================|
- | Copyright (c)1999-2007, Lukas Gebauer |
- | All rights reserved. |
- | |
- | Redistribution and use in source and binary forms, with or without |
- | modification, are permitted provided that the following conditions are met: |
- | |
- | Redistributions of source code must retain the above copyright notice, this |
- | list of conditions and the following disclaimer. |
- | |
- | Redistributions in binary form must reproduce the above copyright notice, |
- | this list of conditions and the following disclaimer in the documentation |
- | and/or other materials provided with the distribution. |
- | |
- | Neither the name of Lukas Gebauer nor the names of its contributors may |
- | be used to endorse or promote products derived from this software without |
- | specific prior written permission. |
- | |
- | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" |
- | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
- | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
- | ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR |
- | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
- | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR |
- | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER |
- | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
- | LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
- | OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH |
- | DAMAGE. |
- |==============================================================================|
- | The Initial Developer of the Original Code is Lukas Gebauer (Czech Republic).|
- | Portions created by Lukas Gebauer are Copyright (c)2000-2007. |
- | All Rights Reserved. |
- |==============================================================================|
- | Contributor(s): |
- |==============================================================================|
- | History: see HISTORY.HTM from distribution package |
- | (Found at URL: http://www.ararat.cz/synapse/) |
- |==============================================================================}
- {:@abstract(ICMP PING implementation.)
- Allows create PING and TRACEROUTE. Or you can diagnose your network.
- This unit using IpHlpApi (on WinXP or higher) if available. Otherwise it trying
- to use RAW sockets.
- Warning: For use of RAW sockets you must have some special rights on some
- systems. So, it working allways when you have administator/root rights.
- Otherwise you can have problems!
- Note: This unit is NOT portable to .NET!
- Use native .NET classes for Ping instead.
- }
- {$IFDEF FPC}
- {$MODE DELPHI}
- {$ENDIF}
- {$Q-}
- {$R-}
- {$H+}
- {$IFDEF CIL}
- Sorry, this unit is not for .NET!
- {$ENDIF}
- unit pingsend;
- interface
- uses
- SysUtils,
- synsock, blcksock, synautil, synafpc, synaip
- {$IFDEF WIN32}
- , windows
- {$ENDIF}
- ;
- const
- ICMP_ECHO = 8;
- ICMP_ECHOREPLY = 0;
- ICMP_UNREACH = 3;
- ICMP_TIME_EXCEEDED = 11;
- //rfc-2292
- ICMP6_ECHO = 128;
- ICMP6_ECHOREPLY = 129;
- ICMP6_UNREACH = 1;
- ICMP6_TIME_EXCEEDED = 3;
- type
- {:List of possible ICMP reply packet types.}
- TICMPError = (
- IE_NoError,
- IE_Other,
- IE_TTLExceed,
- IE_UnreachOther,
- IE_UnreachRoute,
- IE_UnreachAdmin,
- IE_UnreachAddr,
- IE_UnreachPort
- );
- {:@abstract(Implementation of ICMP PING and ICMPv6 PING.)}
- TPINGSend = class(TSynaClient)
- private
- FSock: TICMPBlockSocket;
- FBuffer: string;
- FSeq: Integer;
- FId: Integer;
- FPacketSize: Integer;
- FPingTime: Integer;
- FIcmpEcho: Byte;
- FIcmpEchoReply: Byte;
- FIcmpUnreach: Byte;
- FReplyFrom: string;
- FReplyType: byte;
- FReplyCode: byte;
- FReplyError: TICMPError;
- FReplyErrorDesc: string;
- FTTL: Byte;
- Fsin: TVarSin;
- function Checksum(Value: string): Word;
- function Checksum6(Value: string): Word;
- function ReadPacket: Boolean;
- procedure TranslateError;
- procedure TranslateErrorIpHlp(value: integer);
- function InternalPing(const Host: string): Boolean;
- function InternalPingIpHlp(const Host: string): Boolean;
- function IsHostIP6(const Host: string): Boolean;
- procedure GenErrorDesc;
- public
- {:Send ICMP ping to host and count @link(pingtime). If ping OK, result is
- @true.}
- function Ping(const Host: string): Boolean;
- constructor Create;
- destructor Destroy; override;
- published
- {:Size of PING packet. Default size is 32 bytes.}
- property PacketSize: Integer read FPacketSize Write FPacketSize;
- {:Time between request and reply.}
- property PingTime: Integer read FPingTime;
- {:From this address is sended reply for your PING request. It maybe not your
- requested destination, when some error occured!}
- property ReplyFrom: string read FReplyFrom;
- {:ICMP type of PING reply. Each protocol using another values! For IPv4 and
- IPv6 are used different values!}
- property ReplyType: byte read FReplyType;
- {:ICMP code of PING reply. Each protocol using another values! For IPv4 and
- IPv6 are used different values! For protocol independent value look to
- @link(ReplyError)}
- property ReplyCode: byte read FReplyCode;
- {:Return type of returned ICMP message. This value is independent on used
- protocol!}
- property ReplyError: TICMPError read FReplyError;
- {:Return human readable description of returned packet type.}
- property ReplyErrorDesc: string read FReplyErrorDesc;
- {:Socket object used for TCP/IP operation. Good for seting OnStatus hook, etc.}
- property Sock: TICMPBlockSocket read FSock;
- {:TTL value for ICMP query}
- property TTL: byte read FTTL write FTTL;
- end;
- {:A very useful function and example of its use would be found in the TPINGSend
- object. Use it to ping to any host. If successful, returns the ping time in
- milliseconds. Returns -1 if an error occurred.}
- function PingHost(const Host: string): Integer;
- {:A very useful function and example of its use would be found in the TPINGSend
- object. Use it to TraceRoute to any host.}
- function TraceRouteHost(const Host: string): string;
- implementation
- type
- {:Record for ICMP ECHO packet header.}
- TIcmpEchoHeader = record
- i_type: Byte;
- i_code: Byte;
- i_checkSum: Word;
- i_Id: Word;
- i_seq: Word;
- TimeStamp: integer;
- end;
- {:record used internally by TPingSend for compute checksum of ICMPv6 packet
- pseudoheader.}
- TICMP6Packet = record
- in_source: TInAddr6;
- in_dest: TInAddr6;
- Length: integer;
- free0: Byte;
- free1: Byte;
- free2: Byte;
- proto: Byte;
- end;
- {$IFDEF WIN32}
- const
- DLLIcmpName = 'iphlpapi.dll';
- type
- TIP_OPTION_INFORMATION = packed record
- TTL: Byte;
- TOS: Byte;
- Flags: Byte;
- OptionsSize: Byte;
- OptionsData: PChar;
- end;
- PIP_OPTION_INFORMATION = ^TIP_OPTION_INFORMATION;
- TICMP_ECHO_REPLY = packed record
- Address: TInAddr;
- Status: integer;
- RoundTripTime: integer;
- DataSize: Word;
- Reserved: Word;
- Data: pointer;
- Options: TIP_OPTION_INFORMATION;
- end;
- PICMP_ECHO_REPLY = ^TICMP_ECHO_REPLY;
- TICMPV6_ECHO_REPLY = packed record
- Address: TSockAddrIn6;
- Status: integer;
- RoundTripTime: integer;
- end;
- PICMPV6_ECHO_REPLY = ^TICMPV6_ECHO_REPLY;
- TIcmpCreateFile = function: integer; stdcall;
- TIcmpCloseHandle = function(handle: integer): boolean; stdcall;
- TIcmpSendEcho2 = function(handle: integer; Event: pointer; ApcRoutine: pointer;
- ApcContext: pointer; DestinationAddress: TInAddr; RequestData: pointer;
- RequestSize: integer; RequestOptions: PIP_OPTION_INFORMATION;
- ReplyBuffer: pointer; ReplySize: integer; Timeout: Integer): integer; stdcall;
- TIcmp6CreateFile = function: integer; stdcall;
- TIcmp6SendEcho2 = function(handle: integer; Event: pointer; ApcRoutine: pointer;
- ApcContext: pointer; SourceAddress: PSockAddrIn6; DestinationAddress: PSockAddrIn6;
- RequestData: pointer; RequestSize: integer; RequestOptions: PIP_OPTION_INFORMATION;
- ReplyBuffer: pointer; ReplySize: integer; Timeout: Integer): integer; stdcall;
- var
- IcmpDllHandle: TLibHandle = 0;
- IcmpHelper4: boolean = false;
- IcmpHelper6: boolean = false;
- IcmpCreateFile: TIcmpCreateFile = nil;
- IcmpCloseHandle: TIcmpCloseHandle = nil;
- IcmpSendEcho2: TIcmpSendEcho2 = nil;
- Icmp6CreateFile: TIcmp6CreateFile = nil;
- Icmp6SendEcho2: TIcmp6SendEcho2 = nil;
- {$ENDIF}
- {==============================================================================}
- constructor TPINGSend.Create;
- begin
- inherited Create;
- FSock := TICMPBlockSocket.Create;
- FTimeout := 5000;
- FPacketSize := 32;
- FSeq := 0;
- Randomize;
- FTTL := 128;
- end;
- destructor TPINGSend.Destroy;
- begin
- FSock.Free;
- inherited Destroy;
- end;
- function TPINGSend.ReadPacket: Boolean;
- begin
- FBuffer := FSock.RecvPacket(Ftimeout);
- Result := FSock.LastError = 0;
- end;
- procedure TPINGSend.GenErrorDesc;
- begin
- case FReplyError of
- IE_NoError:
- FReplyErrorDesc := '';
- IE_Other:
- FReplyErrorDesc := 'Unknown error';
- IE_TTLExceed:
- FReplyErrorDesc := 'TTL Exceeded';
- IE_UnreachOther:
- FReplyErrorDesc := 'Unknown unreachable';
- IE_UnreachRoute:
- FReplyErrorDesc := 'No route to destination';
- IE_UnreachAdmin:
- FReplyErrorDesc := 'Administratively prohibited';
- IE_UnreachAddr:
- FReplyErrorDesc := 'Address unreachable';
- IE_UnreachPort:
- FReplyErrorDesc := 'Port unreachable';
- end;
- end;
- function TPINGSend.IsHostIP6(const Host: string): Boolean;
- var
- f: integer;
- begin
- f := AF_UNSPEC;
- if IsIp(Host) then
- f := AF_INET
- else
- if IsIp6(Host) then
- f := AF_INET6;
- synsock.SetVarSin(Fsin, host, '0', f,
- IPPROTO_UDP, SOCK_DGRAM, Fsock.PreferIP4);
- result := Fsin.sin_family = AF_INET6;
- end;
- function TPINGSend.Ping(const Host: string): Boolean;
- var
- b: boolean;
- begin
- FPingTime := -1;
- FReplyFrom := '';
- FReplyType := 0;
- FReplyCode := 0;
- FReplyError := IE_Other;
- GenErrorDesc;
- FBuffer := StringOfChar(#55, SizeOf(TICMPEchoHeader) + FPacketSize);
- {$IFDEF WIN32}
- b := IsHostIP6(host);
- if not(b) and IcmpHelper4 then
- result := InternalPingIpHlp(host)
- else
- if b and IcmpHelper6 then
- result := InternalPingIpHlp(host)
- else
- result := InternalPing(host);
- {$ELSE}
- result := InternalPing(host);
- {$ENDIF}
- end;
- function TPINGSend.InternalPing(const Host: string): Boolean;
- var
- IPHeadPtr: ^TIPHeader;
- IpHdrLen: Integer;
- IcmpEchoHeaderPtr: ^TICMPEchoHeader;
- t: Boolean;
- x: cardinal;
- IcmpReqHead: string;
- begin
- Result := False;
- FSock.TTL := FTTL;
- FSock.Bind(FIPInterface, cAnyPort);
- FSock.Connect(Host, '0');
- if FSock.LastError <> 0 then
- Exit;
- FSock.SizeRecvBuffer := 60 * 1024;
- if FSock.IP6used then
- begin
- FIcmpEcho := ICMP6_ECHO;
- FIcmpEchoReply := ICMP6_ECHOREPLY;
- FIcmpUnreach := ICMP6_UNREACH;
- end
- else
- begin
- FIcmpEcho := ICMP_ECHO;
- FIcmpEchoReply := ICMP_ECHOREPLY;
- FIcmpUnreach := ICMP_UNREACH;
- end;
- IcmpEchoHeaderPtr := Pointer(FBuffer);
- with IcmpEchoHeaderPtr^ do
- begin
- i_type := FIcmpEcho;
- i_code := 0;
- i_CheckSum := 0;
- FId := System.Random(32767);
- i_Id := FId;
- TimeStamp := GetTick;
- Inc(FSeq);
- i_Seq := FSeq;
- if fSock.IP6used then
- i_CheckSum := CheckSum6(FBuffer)
- else
- i_CheckSum := CheckSum(FBuffer);
- end;
- FSock.SendString(FBuffer);
- // remember first 8 bytes of ICMP packet
- IcmpReqHead := Copy(FBuffer, 1, 8);
- x := GetTick;
- repeat
- t := ReadPacket;
- if not t then
- break;
- if fSock.IP6used then
- begin
- {$IFNDEF WIN32}
- IcmpEchoHeaderPtr := Pointer(FBuffer);
- {$ELSE}
- //WinXP SP1 with networking update doing this think by another way ;-O
- // FBuffer := StringOfChar(#0, 4) + FBuffer;
- IcmpEchoHeaderPtr := Pointer(FBuffer);
- // IcmpEchoHeaderPtr^.i_type := FIcmpEchoReply;
- {$ENDIF}
- end
- else
- begin
- IPHeadPtr := Pointer(FBuffer);
- IpHdrLen := (IPHeadPtr^.VerLen and $0F) * 4;
- IcmpEchoHeaderPtr := @FBuffer[IpHdrLen + 1];
- end;
- //check for timeout
- if TickDelta(x, GetTick) > FTimeout then
- begin
- t := false;
- Break;
- end;
- //it discard sometimes possible 'echoes' of previosly sended packet
- //or other unwanted ICMP packets...
- until (IcmpEchoHeaderPtr^.i_type <> FIcmpEcho)
- and ((IcmpEchoHeaderPtr^.i_id = FId)
- or (Pos(IcmpReqHead, FBuffer) > 0));
- if t then
- begin
- FPingTime := TickDelta(x, GetTick);
- FReplyFrom := FSock.GetRemoteSinIP;
- FReplyType := IcmpEchoHeaderPtr^.i_type;
- FReplyCode := IcmpEchoHeaderPtr^.i_code;
- TranslateError;
- Result := True;
- end;
- end;
- function TPINGSend.Checksum(Value: string): Word;
- var
- CkSum: integer;
- Num, Remain: Integer;
- n, i: Integer;
- begin
- Num := Length(Value) div 2;
- Remain := Length(Value) mod 2;
- CkSum := 0;
- i := 1;
- for n := 0 to Num - 1 do
- begin
- CkSum := CkSum + Synsock.HtoNs(DecodeInt(Value, i));
- inc(i, 2);
- end;
- if Remain <> 0 then
- CkSum := CkSum + Ord(Value[Length(Value)]);
- CkSum := (CkSum shr 16) + (CkSum and $FFFF);
- CkSum := CkSum + (CkSum shr 16);
- Result := Word(not CkSum);
- end;
- function TPINGSend.Checksum6(Value: string): Word;
- const
- IOC_OUT = $40000000;
- IOC_IN = $80000000;
- IOC_INOUT = (IOC_IN or IOC_OUT);
- IOC_WS2 = $08000000;
- SIO_ROUTING_INTERFACE_QUERY = 20 or IOC_WS2 or IOC_INOUT;
- var
- ICMP6Ptr: ^TICMP6Packet;
- s: string;
- b: integer;
- ip6: TSockAddrIn6;
- x: integer;
- begin
- Result := 0;
- {$IFDEF WIN32}
- s := StringOfChar(#0, SizeOf(TICMP6Packet)) + Value;
- ICMP6Ptr := Pointer(s);
- x := synsock.WSAIoctl(FSock.Socket, SIO_ROUTING_INTERFACE_QUERY,
- @FSock.RemoteSin, SizeOf(FSock.RemoteSin),
- @ip6, SizeOf(ip6), @b, nil, nil);
- if x <> -1 then
- ICMP6Ptr^.in_dest := ip6.sin6_addr
- else
- ICMP6Ptr^.in_dest := FSock.LocalSin.sin6_addr;
- ICMP6Ptr^.in_source := FSock.RemoteSin.sin6_addr;
- ICMP6Ptr^.Length := synsock.htonl(Length(Value));
- ICMP6Ptr^.proto := IPPROTO_ICMPV6;
- Result := Checksum(s);
- {$ENDIF}
- end;
- procedure TPINGSend.TranslateError;
- begin
- if fSock.IP6used then
- begin
- case FReplyType of
- ICMP6_ECHOREPLY:
- FReplyError := IE_NoError;
- ICMP6_TIME_EXCEEDED:
- FReplyError := IE_TTLExceed;
- ICMP6_UNREACH:
- case FReplyCode of
- 0:
- FReplyError := IE_UnreachRoute;
- 3:
- FReplyError := IE_UnreachAddr;
- 4:
- FReplyError := IE_UnreachPort;
- 1:
- FReplyError := IE_UnreachAdmin;
- else
- FReplyError := IE_UnreachOther;
- end;
- else
- FReplyError := IE_Other;
- end;
- end
- else
- begin
- case FReplyType of
- ICMP_ECHOREPLY:
- FReplyError := IE_NoError;
- ICMP_TIME_EXCEEDED:
- FReplyError := IE_TTLExceed;
- ICMP_UNREACH:
- case FReplyCode of
- 0:
- FReplyError := IE_UnreachRoute;
- 1:
- FReplyError := IE_UnreachAddr;
- 3:
- FReplyError := IE_UnreachPort;
- 13:
- FReplyError := IE_UnreachAdmin;
- else
- FReplyError := IE_UnreachOther;
- end;
- else
- FReplyError := IE_Other;
- end;
- end;
- GenErrorDesc;
- end;
- procedure TPINGSend.TranslateErrorIpHlp(value: integer);
- begin
- case value of
- 11000, 0:
- FReplyError := IE_NoError;
- 11013:
- FReplyError := IE_TTLExceed;
- 11002:
- FReplyError := IE_UnreachRoute;
- 11003:
- FReplyError := IE_UnreachAddr;
- 11005:
- FReplyError := IE_UnreachPort;
- 11004:
- FReplyError := IE_UnreachAdmin;
- else
- FReplyError := IE_Other;
- end;
- GenErrorDesc;
- end;
- function TPINGSend.InternalPingIpHlp(const Host: string): Boolean;
- {$IFDEF WIN32}
- var
- PingIp6: boolean;
- PingHandle: integer;
- r: integer;
- ipo: TIP_OPTION_INFORMATION;
- RBuff: string;
- ip4reply: PICMP_ECHO_REPLY;
- ip6reply: PICMPV6_ECHO_REPLY;
- ip6: TSockAddrIn6;
- begin
- Result := False;
- PingIp6 := Fsin.sin_family = AF_INET6;
- if pingIp6 then
- PingHandle := Icmp6CreateFile
- else
- PingHandle := IcmpCreateFile;
- if PingHandle <> -1 then
- begin
- try
- ipo.TTL := FTTL;
- ipo.TOS := 0;
- ipo.Flags := 0;
- ipo.OptionsSize := 0;
- ipo.OptionsData := nil;
- setlength(RBuff, 4096);
- if pingIp6 then
- begin
- FillChar(ip6, sizeof(ip6), 0);
- r := Icmp6SendEcho2(PingHandle, nil, nil, nil, @ip6, @Fsin,
- Pchar(FBuffer), length(FBuffer), @ipo, pchar(RBuff), length(RBuff), FTimeout);
- if r > 0 then
- begin
- RBuff := #0 + #0 + RBuff;
- ip6reply := PICMPV6_ECHO_REPLY(pointer(RBuff));
- FPingTime := ip6reply^.RoundTripTime;
- ip6reply^.Address.sin6_family := AF_INET6;
- FReplyFrom := GetSinIp(TVarSin(ip6reply^.Address));
- TranslateErrorIpHlp(ip6reply^.Status);
- Result := True;
- end;
- end
- else
- begin
- r := IcmpSendEcho2(PingHandle, nil, nil, nil, Fsin.sin_addr,
- Pchar(FBuffer), length(FBuffer), @ipo, pchar(RBuff), length(RBuff), FTimeout);
- if r > 0 then
- begin
- ip4reply := PICMP_ECHO_REPLY(pointer(RBuff));
- FPingTime := ip4reply^.RoundTripTime;
- FReplyFrom := IpToStr(swapbytes(ip4reply^.Address.S_addr));
- TranslateErrorIpHlp(ip4reply^.Status);
- Result := True;
- end;
- end
- finally
- IcmpCloseHandle(PingHandle);
- end;
- end;
- end;
- {$ELSE}
- begin
- result := false;
- end;
- {$ENDIF}
- {==============================================================================}
- function PingHost(const Host: string): Integer;
- begin
- with TPINGSend.Create do
- try
- Result := -1;
- if Ping(Host) then
- if ReplyError = IE_NoError then
- Result := PingTime;
- finally
- Free;
- end;
- end;
- function TraceRouteHost(const Host: string): string;
- var
- Ping: TPingSend;
- ttl : byte;
- begin
- Result := '';
- Ping := TPINGSend.Create;
- try
- ttl := 1;
- repeat
- ping.TTL := ttl;
- inc(ttl);
- if ttl > 30 then
- Break;
- if not ping.Ping(Host) then
- begin
- Result := Result + cAnyHost+ ' Timeout' + CRLF;
- continue;
- end;
- if (ping.ReplyError <> IE_NoError)
- and (ping.ReplyError <> IE_TTLExceed) then
- begin
- Result := Result + Ping.ReplyFrom + ' ' + Ping.ReplyErrorDesc + CRLF;
- break;
- end;
- Result := Result + Ping.ReplyFrom + ' ' + IntToStr(Ping.PingTime) + CRLF;
- until ping.ReplyError = IE_NoError;
- finally
- Ping.Free;
- end;
- end;
- {$IFDEF WIN32}
- initialization
- begin
- IcmpHelper4 := false;
- IcmpHelper6 := false;
- IcmpDllHandle := LoadLibrary(DLLIcmpName);
- if IcmpDllHandle <> 0 then
- begin
- IcmpCreateFile := GetProcAddress(IcmpDLLHandle, 'IcmpCreateFile');
- IcmpCloseHandle := GetProcAddress(IcmpDLLHandle, 'IcmpCloseHandle');
- IcmpSendEcho2 := GetProcAddress(IcmpDLLHandle, 'IcmpSendEcho2');
- Icmp6CreateFile := GetProcAddress(IcmpDLLHandle, 'Icmp6CreateFile');
- Icmp6SendEcho2 := GetProcAddress(IcmpDLLHandle, 'Icmp6SendEcho2');
- IcmpHelper4 := assigned(IcmpCreateFile)
- and assigned(IcmpCloseHandle)
- and assigned(IcmpSendEcho2);
- IcmpHelper6 := assigned(Icmp6CreateFile)
- and assigned(Icmp6SendEcho2);
- end;
- end;
- finalization
- begin
- FreeLibrary(IcmpDllHandle);
- end;
- {$ENDIF}
- end.
|