Protocol independent ping client code [Windows]

Share your advanced PureBasic knowledge/code with the community.
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Protocol independent ping client code [Windows]

Post by SFSxOI »

Came across this while cleaning up and thought someone may have a use for it. I have not seen much Ipv6 code posted using the IcmpSendEcho2Ex function and of course there is nothing for IPv6 posted (i think) using the Icmp6SendEcho2 function other than what i've posted already. So.... anyway......this is protocol independent and accepts addresses in either Ipv6 hexidecimal or Ipv4 dotted-decimal or named addresses for either Ipv4 or Ipv6, the structures are for protocol independent use and take either Ipv4 or Ipv6. Yes, it uses API, change it around as you wish. For Windows Vista or above, PureBasic 5.0. the production code worked for both x86 an 64 bit but i've changed some things around in cleaning this up to post and have not checked it on 64 bit after the changes and I only checked this posted code on x86.

Code: Select all

Prototype PGetAddrInfoEx(pName, pServiceName, dwNameSpace, lpNspId, pHints, ppResult, timeout, lpOverlapped, lpCompletionRoutine, lpNameHandle)
Prototype PWSAStartup(wVersionRequested, lpWSAData)
Prototype PWSACleanup()
Prototype PFreeAddrInfoEx(ai)
Prototype PIcmp6SendEcho2(IcmpHandle, Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData, RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout)
Prototype PIcmp6CreateFile()
Prototype PIcmpCreateFile()
Prototype PWSAGetLastError()
Prototype PIcmpSendEcho2Ex(IcmpHandle, Event, ApcRoutine, ApcContext, SourceAddress, DestinationAddress, RequestData, RequestSize, RequestOptions, ReplyBuffer, ReplySize, Timeout)

Global GetAddrInfoEx.PGetAddrInfoEx
Global WSAStartup.PWSAStartup
Global WSACleanup.PWSACleanup
Global FreeAddrInfoEx.PFreeAddrInfoEx
Global Icmp6SendEcho2.PIcmp6SendEcho2
Global Icmp6CreateFile.PIcmp6CreateFile
Global IcmpCreateFile.PIcmpCreateFile
Global WSAGetLastError.PWSAGetLastError
Global IcmpSendEcho2Ex.PIcmpSendEcho2Ex

Structure SOCKADDR_STORAGE ;->Structure SOCKADDR_STORAGE
  ss_family.l
  __ss_pad1.b[6]
  __ss_align.q
  __ss_pad2.b[112]
EndStructure

Structure SOCKET_ADDRESS ;->Structure SOCKET_ADDRESS
*lpSockaddr.SOCKADDR_STORAGE
  iSockaddrLength.l
EndStructure

Structure ADDRINFOEX ;->Structure ADDRINFOEX
  ai_flags.l
  ai_family.l
  ai_socktype.l
  ai_protocol.l
  ai_addrlen.i
  *ai_canonname.c 
  *ai_addr.SOCKET_ADDRESS
  *ai_blob
  ai_bloblen.i
  ai_provider.l
  *ai_next.ADDRINFOEX
EndStructure

Structure IPV6_ADDRESS_EX ;->Structure IPV6_ADDRESS_EX
  sin6_port.w
  sin6_flowinfo.l
  sin6_addr.w[8]
  sin6_scope_id.l
EndStructure

Structure ICMPV6_ECHO_REPLY ;->Structure ICMPV6_ECHO_REPLY
  Address.IPV6_ADDRESS_EX
  Status.l
  RoundTripTime.i
EndStructure

#DEFAULT_SEND_SIZE = 32
#REQUEST_DATA_SIZE = 32
#DEFAULT_BUFFER_SIZE = 8184
#MAX_BUFFER_SIZE = 65536
#NS_DNS = 12
#AF_INET6 = 23
#AI_SECURE = $08000

If Lib_iphlpapi : CloseLibrary(Lib_iphlpapi) : EndIf
If Lib_Winsock : CloseLibrary(Lib_Winsock) : EndIf

Procedure LoadLibraries()
  ;Global Lib_iphlpapi.l, Lib_Winsock.l
    
Lib_iphlpapi = OpenLibrary(#PB_Any,"iphlpapi.dll")
If IsLibrary(Lib_iphlpapi)<> 0
  IcmpSendEcho2Ex.PIcmpSendEcho2Ex=GetFunction(Lib_iphlpapi,"IcmpSendEcho2Ex")
  Icmp6SendEcho2.PIcmp6SendEcho2=GetFunction(Lib_iphlpapi,"Icmp6SendEcho2")
  Icmp6CreateFile.PIcmp6CreateFile=GetFunction(Lib_iphlpapi,"Icmp6CreateFile")
  IcmpCreateFile.PIcmpCreateFile=GetFunction(Lib_iphlpapi,"IcmpCreateFile")
EndIf

Lib_Winsock = OpenLibrary(#PB_Any,"ws2_32.dll")
If IsLibrary(Lib_Winsock)<> 0
  WSAStartup.PWSAStartup=GetFunction(Lib_Winsock,"WSAStartup")
  WSACleanup.PWSACleanup=GetFunction(Lib_Winsock,"WSACleanup")
  WSAGetLastError.PWSAGetLastError=GetFunction(Lib_Winsock,"WSAGetLastError")
  CompilerIf #PB_Compiler_Unicode ; if compiled in unicode use this
    FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoExW")
    GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExW")
  CompilerElse ; if not compiled in unicode use this
    FreeAddrInfoEx.PFreeAddrInfoEx=GetFunction(Lib_Winsock,"FreeAddrInfoEx")
    GetAddrInfoEx.PGetAddrInfoEx=GetFunction(Lib_Winsock,"GetAddrInfoExA")
  CompilerEndIf
EndIf

EndProcedure

Macro MAKEWORD(a, b)
  (a & $FF)|((b & $FF)<<8)
EndMacro

Procedure Ipv46PingConnectTest(DIPinAdr$, family.l)
  Protected ICMPVSucess.b, SendDataSize.i, ReplyResultSize.i, NumberOfReplies.i, IcmpFileHandle.l, TimeOut.i
  Protected SendPacketDataInfo$, DestinationIPAddress$
  Protected *LocalComp.ADDRINFOEX, *dest.ADDRINFOEX, *Echo.ICMP_ECHO_REPLY, *SendData, *ReplyResult
  
  DestinationIPAddress$ = DIPinAdr$
  TimeOut = 5000
      
  SendPacketDataInfo$ = "HELLO"
  *SendData = AllocateMemory(#REQUEST_DATA_SIZE)
  *prequestData = *SendData
  CopyMemoryString(@SendPacketDataInfo$, @*prequestData)
  CompilerIf #PB_Compiler_Unicode
    SendDataSize = StringByteLength(PeekS(*SendData)) + 2
  CompilerElse
    SendDataSize = StringByteLength(PeekS(*SendData)) + 1
  CompilerEndIf
  If SendDataSize <= #DEFAULT_SEND_SIZE
    ReplyResultSize = #DEFAULT_BUFFER_SIZE
  Else
    ReplyResultSize = #MAX_BUFFER_SIZE
  EndIf
  
  ; local address - structure needs to exist for use with IcmpSendEcho2Ex but not filled with local address
  ;localaddress$ = "127.0.0.1" for IPv4 - and - localaddress$ = "::1" for IPv6 = loopback addreses
  ; windows uses the loopback address automatically so we don't feed *LocalComp an address but still needs to be
  ; declaired for the IcmpSendEcho2Ex and Icmp6SendEcho2 functions
  *LocalComp.ADDRINFOEX = AllocateMemory(SizeOf(ADDRINFOEX))
  *LocalComp\ai_family = family
  
  ; destination address
  *dest.ADDRINFOEX = AllocateMemory(SizeOf(ADDRINFOEX))
  *dest\ai_family = family
  *dest\ai_flags = #AI_SECURE
  
  ; if using GetAddrInfoEx then use FreeAddrInfoEx to free - GetAddrInfoEx is used when ADDRINFOEX structure is used
   GetAddrInfoEx(@DestinationIPAddress$, #Null, #NS_DNS, #Null, #Null, @*dest, #Null, #Null, #Null, #Null)
  
  *ReplyResult = AllocateMemory(ReplyResultSize)
  
  If family = #AF_INET
    *IPv4Echo.ICMP_ECHO_REPLY = *ReplyResult
    IcmpFileHandle = IcmpCreateFile()
    NumberOfReplies = IcmpSendEcho2Ex(IcmpFileHandle, #Null, #Null, #Null, *LocalComp\ai_addr, *dest\ai_addr\lpSockaddr, *SendData, SendDataSize, #Null, *ReplyResult, ReplyResultSize, TimeOut)
    AddressPing$ = "IPv4 address pinged was = " + DestinationIPAddress$
  ElseIf family = #AF_INET6
    *IPv6Echo.ICMPV6_ECHO_REPLY = *ReplyResult
    IcmpFileHandle = Icmp6CreateFile()
    numberOfReplies = Icmp6SendEcho2(IcmpFileHandle, #Null, #Null, #Null, *LocalComp, *dest\ai_addr, *SendData, SendDataSize, #Null, *ReplyResult, ReplyResultSize, TimeOut)
    AddressPing$ = "IPv6 address pinged was = " + DestinationIPAddress$
  EndIf
  
  Select WSAGetLastError()
    Case 0
      errmsg$ = "Success"
    Case 1231
      errmsg$ = "The network location cannot be reached"
    Case 11001
      errmsg$ = "Buffer Too Small"
    Case 11002
      errmsg$ = "Destination Net Unreachable"
    Case 11003
      errmsg$ = "Destination Host Unreachable"
    Case 11004
      errmsg$ = "Destination Protocol Unreachable"
    Case 11005
      errmsg$ = "Destination Port Unreachable"
    Case 11006
      errmsg$ = "No Resources"
    Case 11007
      errmsg$ = "Bad Option"
    Case 11008
      errmsg$ = "Hardware Error"
    Case 11009
      errmsg$ = "Packet Too Big"
    Case 11010
      errmsg$ = "Request Timed Out"
    Case 11011
      errmsg$ = "Bad Request"
    Case 11012
      errmsg$ = "Bad Route"
    Case 11013
      errmsg$ = "TimeToLive Expired Transit"
    Case 11014
      errmsg$ = "TimeToLive Expired Reassembly"
    Case 11015
      errmsg$ = "Parameter Problem"
    Case 11016
      errmsg$ = "Source Quench"
    Case 11017
      errmsg$ = "Option Too Big"
    Case 11018
      errmsg$ = "Negotiating IPSEC"
    Case 11050
      errmsg$ = "General Failure"
    Default
      errmsg$ = "Unknown Status or Failure"
  EndSelect
  
  Debug AddressPing$
  Debug "The result status of the ping was = " + errmsg$
  
  If NumberOfReplies > 0
    ICMPVSucess = #True
  Else
    ICMPVSucess = #False
  EndIf
  
  IcmpCloseHandle_(IcmpFileHandle)
  FreeMemory(*ReplyResult)
  FreeMemory(*SendData)
  FreeMemory(*LocalComp)
  FreeAddrInfoEx(*dest)
  
  ProcedureReturn ICMPVSucess
  
EndProcedure

LoadLibraries()
wVersionRequested.w = MAKEWORD(2,2)
WSAStart.i = WSAStartup(wVersionRequested,@wsaData.WSADATA)

Debug "**********************************************************"
Debug Ipv46PingConnectTest("www.google.com", #AF_INET) ; google
Debug "**********************************************************"

Debug "**********************************************************"
Debug Ipv46PingConnectTest("74.125.130.105", #AF_INET) ; google
Debug "**********************************************************"
 
Debug "**********************************************************"
Debug Ipv46PingConnectTest("2620:0:1cfe:face:b00c::3", #AF_INET6) ; facebook ipv6 hex address
Debug "**********************************************************"
; ;Delay(1000)
Debug Ipv46PingConnectTest("www.v6.facebook.com", #AF_INET6) ; facebook named Ipv6 address
Debug "**********************************************************"


WSACleanup()
Last edited by SFSxOI on Mon Jan 07, 2013 1:23 pm, edited 2 times in total.
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
dige
Addict
Addict
Posts: 1247
Joined: Wed Apr 30, 2003 8:15 am
Location: Germany
Contact:

Re: Protocol independent ping client code

Post by dige »

@SFSxOI, I would like to test it, but it does not run on pb5.10, coz of forbidden native pointer. Could you please update the code?
"Daddy, I'll run faster, then it is not so far..."
SFSxOI
Addict
Addict
Posts: 2970
Joined: Sat Dec 31, 2005 5:24 pm
Location: Where ya would never look.....

Re: Protocol independent ping client code

Post by SFSxOI »

dige wrote:@SFSxOI, I would like to test it, but it does not run on pb5.10, coz of forbidden native pointer. Could you please update the code?

for PB 5.10 beta change this:

Code: Select all

Protected *LocalComp.ADDRINFOEX, *dest.ADDRINFOEX, *Echo.ICMP_ECHO_REPLY, *SendData.c, *ReplyResult.c
to this - remove the types for *SendData and *ReplyResult, e.g. :

Code: Select all

Protected *LocalComp.ADDRINFOEX, *dest.ADDRINFOEX, *Echo.ICMP_ECHO_REPLY, *SendData, *ReplyResult ; removed the character .c type
In Pb 5.10 beta (and furture Purebasic versions maybe?) you can't type pointers with native types, character (.c) is a native type for Purebasic. Updated the code in the first post for the same also, will still run on Pb 5.0 just fine, don't need to and should not type native type pointers anyway
The advantage of a 64 bit operating system over a 32 bit operating system comes down to only being twice the headache.
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Protocol independent ping client code [Windows]

Post by Michael Vogel »

Was wondering why purebasic doesn't support IcmpSendEcho2Ex_(), just IcmpSendEcho_() and IcmpSendEcho2_()?

I do need to define the source address while doing echo requests (to change options like TTL or dont fragment can be done with the simpler functions as well).

The code above does shows an error (invalid memory access) here when calling Icmp6SendEcho2 for "www.v6.facebook.com".
jassing
Addict
Addict
Posts: 1745
Joined: Wed Feb 17, 2010 12:00 am

Re: Protocol independent ping client code [Windows]

Post by jassing »

Not to be too pedantic, but ICMP is a protocol (it's even the 'P' in ICMP)
User avatar
Michael Vogel
Addict
Addict
Posts: 2666
Joined: Thu Feb 09, 2006 11:27 pm
Contact:

Re: Protocol independent ping client code [Windows]

Post by Michael Vogel »

@jassing - who was denying that? :?
jassing
Addict
Addict
Posts: 1745
Joined: Wed Feb 17, 2010 12:00 am

Re: Protocol independent ping client code [Windows]

Post by jassing »

Michael Vogel wrote: Thu Jun 08, 2023 3:07 pm @jassing - who was denying that? :?
The title... "protocol independent ping client
was just clarifying that it's not independent, it is dependent on icmp... that's all.
Post Reply