Jump to content

getaddrinfo timeout


Go to solution Solved by funkey,

Recommended Posts

Hi,

I was looking for a multi threading Ping and found this post () from Fr0zt.

His Ping in assembly is impressive (adapted from the trancexx's and monoceres work  ?do=embed' frameborder='0' data-embedContent>)'>?do=embed' frameborder='0' data-embedContent>).

#include <Memory.au3>
#include <Array.au3>

Opt('MustDeclareVars', 1)
HotKeySet("{ESC}", "_Exit")
Global Const $DONT_FRAGMENT = 2, $IP_SUCCESS = 0, $IP_DEST_NET_UNREACHABLE = 11002, $IP_DEST_HOST_UNREACHABLE = 11003, $IP_DEST_PROT_UNREACHABLE = 11004, $IP_DEST_PORT_UNREACHABLE = 11005, _
    $IP_NO_RESOURCES = 11006, $IP_HW_ERROR = 11008, $IP_PACKET_TOO_BIG = 11009, $IP_REQ_TIMED_OUT = 11010, $IP_BAD_REQ = 11011, $IP_BAD_ROUTE = 11012, _
    $IP_TTL_EXPIRED_TRANSIT = 11013, $IP_TTL_EXPIRED_REASSEM = 11014, $IP_PARAM_PROBLEM = 11015, $IP_SOURCE_QUENCH = 11016, $IP_BAD_DESTINATION =11018, _
    $IP_GENERAL_FAILURE = 11050, $NO_STATUS = 10000     ;We will use 10000 as the no status indicator since 0 meens successful reply

Local $hPointers = DllStructCreate("ptr IcmpCloseHandle;ptr IcmpSendEcho;ptr IcmpCreateFile;ptr ExitThread")

Global $hkernel32Dll = DllOpen("kernel32.dll")
Global $hKrn = _WinAPI_GetModuleHandle("kernel32.dll")
DllStructSetData($hPointers,"ExitThread",GetProcAddress($hKrn, "ExitThread"))
Global $hICMPDll = LibLoad("ICMP.dll");Iphlpapi.dll")
DllStructSetData($hPointers,"IcmpCloseHandle",GetProcAddress($hICMPDll, "IcmpCloseHandle"))
DllStructSetData($hPointers,"IcmpSendEcho",GetProcAddress($hICMPDll, "IcmpSendEcho"))
DllStructSetData($hPointers,"IcmpCreateFile",GetProcAddress($hICMPDll, "IcmpCreateFile"))

TCPStartup() ;This is required, not only to do DNS lookup, but also for WSAStartup()

Global $pings[1]  = [0]  ;This array will hold all echo reply data in a struct.
ConsoleWrite("Press esc any time to stop" & @CRLF)
pingThreaded("www.google.ca")
pingThreaded("www.asus.com.tw")
Local $pingdata = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
Local $timeout = 150
Local $ttl = 255
pingThreaded("www.autoitscript.com", $timeout, $pingdata, $ttl, $DONT_FRAGMENT)

While 1
    _managePings()
WEnd

;Function pingThreaded
;$ip_addr will accept valid DNS Name or Normal IP address.
;Timouts only really work when an IP isn't responding. Thats important to remember because if you think you can timeout an IP which has latent responces, you can't!
Func pingThreaded($ip_addr, $timeout=5000, $data="x", $ttl=255, $flags=0)
    Local $hexIP = encodeIP($ip_addr)
    If $hexIP == 0 Then Return 0
    Local $pingID = _addPing($ip_addr)
    If IsNumber($ttl) = 0 Or Number($ttl) > 255 Then $ttl = 255
    If IsNumber($timeout) = 0 Or Number($timeout) > 5000 Then $timeout = 5000
    If StringLen($data) > 256 Then $data = StringTrimRight($data,StringLen($data) - 256)
    If IsNumber($flags) = 0 Or Number($flags) > 2 Then $flags = 2
    DllStructSetData($pings[$pingID],"datasize",StringLen($data))   ;We may wish to report the data size later
    ;Props to trancexx
    Local $CodeBuffer = DllStructCreate("byte[696]"); Code=154, Data=256, Echo reply Struct + ICMP_OPTIONS Struct = 286
    Local $RemoteCode = _MemVirtualAlloc(0, DllStructGetSize($CodeBuffer), $MEM_COMMIT, $PAGE_EXECUTE_READWRITE)
    DllStructSetData($CodeBuffer, 1, _
        "0x" & _                                                            ;Original Assembly started at 401000
        "E889000000" & _                                                ;Call 0040108E  <IcmpCreateFile>
        "A3" & SwapEndian($RemoteCode + 410) & _                            ;mov dword ptr [00403010], eax  <hIcmp = IcmpCreateFile Handle>
        "C605" & SwapEndian($RemoteCode + 418) & Hex($ttl,2) & _            ;mov byte ptr [00403024], xx    <TTL>
        "C605" & SwapEndian($RemoteCode + 419) & "00" & _                                   ;mov byte ptr [00403025], 00    <TOS>
        "C605" & SwapEndian($RemoteCode + 420) & Hex($flags,2) & _          ;mov byte ptr [00403026], 02    <Flags, 0x02=DF Bit Set>
        "C605" & SwapEndian($RemoteCode + 421) & "00" & _                   ;mov byte ptr [00403027], 00
        "C705" & SwapEndian($RemoteCode + 422) & "00000000" & _         ;mov dword ptr [00403028], 00000000
        "68" & SwapEndian(Dec(Hex($timeout,4))) & _                                 ;push 0000xxxx  <Timeout>
        "681E010000" & _                                                ;push 0000011E  <Size of Echo reply Struct + ICMP_OPTIONS Struct>
        "68" & SwapEndian($RemoteCode + 426) & _                            ;push 0040302C  <icmpReply>
        "68" & SwapEndian($RemoteCode + 418) & _                            ;push 00403024  <icmpOptions>
        "6A" & Hex(StringLen($data),2) & _                                  ;push 000000xx  <Data Size>
        "68" & SwapEndian($RemoteCode + 154) & _                            ;push 00403000  <Data>
        "68" & SwapEndian(Dec($hexIP)) & _                              ;push <Hex(IP ADDRESS)>
        "FF35" & SwapEndian($RemoteCode + 410) & _                      ;push dword ptr [00403010]  <hIcmp>
        "E839000000" & _                                                ;Call 00401094  <IcmpSendEcho>
        "A1" & SwapEndian($RemoteCode + 434) & _                            ;mov eax, dword ptr [00403034]  <Get the ms responce time from icmpReply.RoundTripTime>
        "A3" & SwapEndian(DllStructGetPtr($pings[$pingID],"reply")) & _         ;mov dword ptr [0040301C], eax  <Store the ms responce time>
        "A1" & SwapEndian($RemoteCode + 430) & _                            ;mov eax, dword ptr [00403030]  <Get the status from icmpReply.Status>
        "A3" & SwapEndian(DllStructGetPtr($pings[$pingID],"status")) & _        ;mov dword ptr [00403020], eax  <Store the status>
        "FF35" & SwapEndian($RemoteCode + 410) & _                      ;push dword ptr [00403010]  <hIcmp>
        "E80E000000" & _                                                ;Call 00401088  <IcmpCloseHandle>
        "6A00" & _                                                      ;push 00000000
        "E801000000" & _                                                ;Call 00401082  <ExitThread>
        "CC" & _                                                            ;int 03
        "FF25" & SwapEndian(DllStructGetPtr($hPointers,"ExitThread")) & _       ;JMP dword ptr  <kernel32.ExitThread>
        "FF25" & SwapEndian(DllStructGetPtr($hPointers,"IcmpCloseHandle")) & _  ;JMP dword ptr  <ICMP.IcmpCloseHandle>
        "FF25" & SwapEndian(DllStructGetPtr($hPointers,"IcmpCreateFile")) & _   ;JMP dword ptr  <ICMP.IcmpCreateFile>
        "FF25" & SwapEndian(DllStructGetPtr($hPointers,"IcmpSendEcho"))& _  ;JMP dword ptr  <ICMP.IcmpSendEcho>
        SwapEndian(StringToBinary($data)) _                             ;This is our ping Data, Max 256 bytes of space here.
    )
    _MemMoveMemory(DllStructGetPtr($CodeBuffer), $RemoteCode, DllStructGetSize($CodeBuffer))
    Local $aCall = DllCall($hkernel32Dll, "ptr", "CreateThread", "ptr", 0, "int", 0, "ptr", $RemoteCode, "ptr", 0, "int", 0, "dword*", 0)
    Return $aCall[0]
EndFunc


;Function _addPing is just for array management of the $pings[] array.
Func _addPing($ip_addr)
    $pings[0] = UBound($pings)
    ReDim $pings[$pings[0]+1]
    $pings[$pings[0]] = DllStructCreate("char ip[" & StringLen($ip_addr) & "];ulong reply;ulong status;int datasize");You could add a timeout struct here
    DllStructSetData($pings[$pings[0]],"ip",$ip_addr)
    DllStructSetData($pings[$pings[0]],"status",$NO_STATUS)
    Return $pings[0]
EndFunc

;Function _removePing is just for array management of the $pings[] array.
Func _removePing($pingID)
    If $pingID > $pings[0] Then Return ;Ensure our ID is valid
    $pings[$pingID] = 0 ;Free the DLLStruct
    _ArrayDelete($pings,$pingID)
    $pings[0] -= 1
EndFunc

;Function _managePings()
;This is where the reply's get sorted out, and actions taken
Func _managePings()
    Local $pingID, $status
    $pingID = 1
    While $pingID <= $pings[0]
        $status = DllStructGetData($pings[$pingID],"status")
        If $status <> $NO_STATUS Then
            Switch $status
                Case $IP_SUCCESS
                    If DllStructGetData($pings[$pingID],"reply") = 0 Then
                        ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " replied in <1ms" & @CRLF)
                    Else
                        ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " replied in " & DllStructGetData($pings[$pingID],"reply") & "ms" & @CRLF)
                    EndIf
                Case $IP_REQ_TIMED_OUT
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " timed-out" & @CRLF)
                Case $IP_DEST_NET_UNREACHABLE
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " The destination network was unreachable." & @CRLF)
                Case $IP_DEST_HOST_UNREACHABLE
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " The destination host was unreachable." & @CRLF)
                Case $IP_DEST_PROT_UNREACHABLE
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " The destination protocol was unreachable." & @CRLF)
                Case $IP_DEST_PORT_UNREACHABLE
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " The destination port was unreachable." & @CRLF)
                Case $IP_NO_RESOURCES
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " Insufficient IP resources were available." & @CRLF)
                Case $IP_HW_ERROR
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " A hardware error occurred." & @CRLF)
                Case $IP_PACKET_TOO_BIG
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " The packet was too big." & @CRLF)
                Case $IP_BAD_REQ
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " A bad request." & @CRLF)
                Case $IP_BAD_ROUTE
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " A bad route." & @CRLF)
                Case $IP_TTL_EXPIRED_TRANSIT
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " The time to live (TTL) expired in transit." & @CRLF) 
                Case $IP_TTL_EXPIRED_REASSEM
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " The time to live expired during fragment reassembly." & @CRLF)
                Case $IP_PARAM_PROBLEM
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " A parameter problem." & @CRLF)
                Case $IP_SOURCE_QUENCH
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " Datagrams are arriving too fast to be processed and datagrams may have been discarded." & @CRLF)
                Case $IP_BAD_DESTINATION
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " A bad destination." & @CRLF)
                Case $IP_GENERAL_FAILURE
                    ConsoleWrite("Ping with " & DllStructGetData($pings[$pingID],"datasize") & " byte(s) to " & DllStructGetData($pings[$pingID],"ip") & " A general failure. This error can be returned for some malformed ICMP packets or lost network connection." & @CRLF)
            EndSwitch
            _removePing($pingID)
    EndIf
;   You may wish to include a feature which can timeout manually here. Just remember if you do that, do not destroy the dllstruct for the ping 
;   because likelly the ping thread will still write to it when it's done.  You will have to wait for that to happen before you destroy it.
        $pingID += 1
    WEnd
EndFunc

Func encodeIP($ip_addr)
    Local $ip_addr_temp = $ip_addr
    If Not _isIP($ip_addr) Then $ip_addr = TCPNameToIP($ip_addr)
        If Not _isIP($ip_addr) Then
        ConsoleWrite($ip_addr_temp & " is not a valid IP Address. If you supplied a hostname ensure DNS is available." & @CRLF)
        Return 0
    EndIf
    Return getHexIP($ip_addr)
EndFunc

Func getHexIP($ip_addr)
    Return Hex(_getIPOctet($ip_addr,4),2) & Hex(_getIPOctet($ip_addr,3),2) & Hex(_getIPOctet($ip_addr,2),2) & Hex(_getIPOctet($ip_addr,1),2)
EndFunc

Func LibLoad($lpLibFileName)
    Local $LibHandle = DllCall($hkernel32Dll, "int", "LoadLibraryA", "str", $lpLibFileName)
    Return $LibHandle[0]
EndFunc

Func LibFree($DllHandle)
    Local $LibFreed = DllCall($hkernel32Dll, "int", "FreeLibrary", "int", $DllHandle)
    return $LibFreed[0]
EndFunc

Func GetProcAddress( $hModule, $lpProcName)
    Local $ProcessAddy = DllCall($hkernel32Dll,"int","GetProcAddress","int",$hModule,"str",$lpProcName)
    Return $ProcessAddy[0]
EndFunc

Func SwapEndian($hex)
    ;trancexx
    Return Hex(Binary($hex))
EndFunc

Func _getIPOctet($ip_addr,$octet=1)
    Switch $octet
        Case 1
        Return Int(StringMid($ip_addr,1,StringInStr($ip_addr,".")))
    Case 4
        Return Int(StringMid($ip_addr,StringInStr($ip_addr,".",0,3)+1))
    Case Else
        Return Int(StringMid($ip_addr,StringInStr($ip_addr,".",0,$octet - 1)+1,StringInStr($ip_addr,".",0,$octet)+1))
    EndSwitch
EndFunc

Func _isIP($text)
    Return StringRegExp($text, "(((25[0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9]))\.){3}((25[0-5])|(2[0-4][0-9])|(1[0-9][0-9])|([1-9]?[0-9]))")
EndFunc

Func _Exit()
    TCPShutdown()
    LibFree($hICMPDll)
    DllClose($hkernel32Dll)
    Exit
EndFunc

I tryed it with HOSTNAMES (instead of ip addresses)  from my network.

But when the computer is offline, the script is pretty slow. It comes from the TCPNameToIP() function and, I suppose, the getaddrinfo Windows function behind.

It seems there is no timeout parameter to pass to this function. So my question is : Is there a way to add a timeout ?

Edited by tatane
Link to comment
Share on other sites

why don't you use local ip addr?

those hosts names are specified in your DNS? Or you used hosts file?

Heroes, there is no such thing

One day I'll discover what IE.au3 has of special for so many users using it.
C'mon there's InetRead and WinHTTP, way better
happy.png

Link to comment
Share on other sites

I can't use local ip address because they are distributed by dhcp. So I'm using a host file.

It seems GetAddrInfoEx function get a timeout parameter : https://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx

But I don't know how to implement this in Autoit...

Since the timeout parameter of GetAddrInfoEx() is only supported on Windows8 and 2012, I cannot test this function.

But I hope this works.

#include <Array.au3>

Global Const $AF_UNSPEC = 0
Global Const $AF_INET = 2
Global Const $AF_INET6 = 23

Global Const $IPPROTO_TCP = 6
Global Const $IPPROTO_UDP = 17

Global Const $SOCK_STREAM = 1
Global Const $SOCK_DGRAM = 2

Global Const $NS_DNS = 12

Global Const $tagTimeVal = "long tv_sec;long tv_usec"
Global Const $tagAddrInfoEx = "int ai_flags;int ai_family;int ai_socktype;int ai_protocol;UINT_PTR ai_addrlen;ptr ai_canonname;ptr ai_addr;ptr ai_blob;UINT_PTR ai_bloblen;ptr ai_provider;ptr ai_next"
Global Const $tagSockAddr_In = "short sin_family;USHORT sin_port;ULONG sin_addr;char sin_zero[8]"
Global Const $tagSockAddr_In6 = "short sin6_family;USHORT sin6_port;ULONG sin6_flowinfo;byte sin6_addr[16];ULONG sin6_scope_id"

TCPStartup()

Global $Timeout = 1000 ; 1 second timeout
Global $aIP = _GetAddrInfoEx("..localmachine", $Timeout, $AF_INET)
If @error Then
    MsgBox(0, "GetAddrInfoEx", "Error: " & @extended)
Else
    _ArrayDisplay($aIP)
EndIf


TCPShutdown()


;https://msdn.microsoft.com/en-us/library/windows/desktop/ms738518%28v=vs.85%29.aspx
Func _GetAddrInfoEx($sNodeName = "..localmachine", $iTimeout = 0, $AddressFamily = $AF_UNSPEC, $SockType = $SOCK_STREAM, $IpProtocol = $IPPROTO_TCP, $NameSpace = $NS_DNS)
    ;funkey 2015.04.11
    Local $pResult, $tAddrInfoEx, $sIP, $tName, $tTimeout, $pTimeout

    If $iTimeout <> 0 Then
        $tTimeout = DllStructCreate($tagTimeVal)
        $pTimeout = DllStructGetPtr($tTimeout)
        DllStructSetData($tTimeout, "tv_sec", Floor($iTimeout / 1000))
        DllStructSetData($tTimeout, "tv_usec", ($iTimeout - DllStructGetData($tTimeout, "tv_sec") * 1000) * 1000)
    Else
        $pTimeout = 0
    EndIf

    Local $hints = DllStructCreate($tagAddrInfoEx)
    DllStructSetData($hints, "ai_family", $AddressFamily)
    DllStructSetData($hints, "ai_socktype", $SockType)
    DllStructSetData($hints, "ai_protocol", $IpProtocol)

    Local $aRet = DllCall("ws2_32.dll", "int", "GetAddrInfoExW", "wstr", $sNodeName, "ptr", 0, "DWORD", $NameSpace, "ptr", 0, _
            "struct*", $hints, "ptr*", 0, "ptr", $pTimeout, "ptr", 0, "ptr", 0, "ptr", 0)

    If $aRet[0] <> 0 Then Return SetError(1, $aRet[0], 0)

    $pResult = $aRet[6]
    Do
        $tAddrInfoEx = DllStructCreate($tagAddrInfoEx, $pResult)
        Switch DllStructGetData($tAddrInfoEx, "ai_family")
            Case $AF_INET
                If $AddressFamily = $AF_UNSPEC Or $AddressFamily = $AF_INET Then
                    $tName = DllStructCreate($tagSockAddr_In, DllStructGetData($tAddrInfoEx, "ai_addr"))
                    $sIP &= _InetNtop(DllStructGetPtr($tName, "sin_addr"), $AF_INET) & ";"
                EndIf
            Case $AF_INET6
                If $AddressFamily = $AF_UNSPEC Or $AddressFamily = $AF_INET6 Then
                    $tName = DllStructCreate($tagSockAddr_In6, DllStructGetData($tAddrInfoEx, "ai_addr"))
                    $sIP &= _InetNtop(DllStructGetPtr($tName, "sin6_addr"), $AF_INET6) & ";"
                EndIf
        EndSwitch
        $pResult = DllStructGetData($tAddrInfoEx, "ai_next")
    Until $pResult = 0
    _FreeAddrInfoEx($aRet[6])
    Return StringSplit(StringTrimRight($sIP, 1), ";", 2)
EndFunc   ;==>_GetAddrInfoEx

Func _FreeAddrInfoEx($pAddrInfoEx)
    DllCall("ws2_32.dll", "none", "FreeAddrInfoEx", "ptr", $pAddrInfoEx)
EndFunc   ;==>_FreeAddrInfoEx

Func _InetNtop($tIn_Addr, $iFamily = $AF_INET) ;IPv4 and IPv6 --> Vista and above
    Local $tBuffer = DllStructCreate("wchar[46]") ;16 for IPv4, 46 for IPv6
    Local $aRet = DllCall("ws2_32.dll", "wstr", "InetNtopW", "int", $iFamily, "struct*", $tIn_Addr, "struct*", $tBuffer, "int", DllStructGetSize($tBuffer) / 2)
    Return DllStructGetData($tBuffer, 1)
EndFunc   ;==>_InetNtop

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

Thanks a lot for your time.

I tested your script on Win 7 Pro (I don't use Win 8) and unfortunatly I've got an error : 10022. The error is the same with online or offline/wrongHost computer.

The Windows Socket error is :

Invalid argument.

Some invalid argument was supplied (for example, specifying an invalid level to the setsockopt function). In some instances, it also refers to the current state of the socket—for instance, calling accept on a socket that is not listening.

EDIT : I tried to replace $NS_DNS by $NS_NETBT (13) but error is the same.

Is there a way in Autoit to implement this UNICODE macro ?

timeout [in, optional]

An optional parameter indicating the time, in milliseconds, to wait for a response from the namespace provider before aborting the call.

This parameter is only supported when the UNICODE or _UNICODE macro has been defined in the sources before calling the GetAddrInfoEx function. Otherwise, this parameter is currently reserved and must be set to NULL since a timeout option is not supported.

Edited by tatane
Link to comment
Share on other sites

I told you that the timeout only works on Win8. I use the Unicode version of the function (GetAddrInfoExW).

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

  • Solution

Hello. Here is the WSAAsyncGetHostByName() function to use with timeout. I tried to make the function as easy as possible. Hope this now works for you.

Global Const $AF_INET = 2
Global Const $tagHostent = "ptr h_name;ptr h_aliases;short h_addrtype;short h_length;ptr h_addr_list"

Global $WSAAsyncGetHostByName_lParam = 0

TCPStartup()

Local $sAddress = "..localmachine"
Global $Timeout = 1000 ; 1 second timeout

Global $sIP = _WSAAsyncGetHostByName_Timeout($sAddress, $Timeout)
If @error Then
    MsgBox(0, $sAddress, "Error: " & @error)
Else
    MsgBox(0, $sAddress, "IP address: " & $sIP)
EndIf

TCPShutdown()

Func _WSAAsyncGetHostByName_Timeout($sNodeName = "..localmachine", $iTimeout = 0, $hGui = Default, $wMsg = Default)
    ;funkey 2015.04.13
    Local Const $WM_USER = 0x400
    Local Const $MAXGETHOSTSTRUCT = 1024

    Local $bGuiDelete = False

    If $wMsg = Default Then $wMsg = $WM_USER + 0x99
    If $hGui = Default Then
        $hGui = GUICreate("_WSAAsyncGetHostByName_Timeout")
        $bGuiDelete = True
    EndIf

    GUIRegisterMsg($wMsg, "_WSAAsyncGetHostByName_Callback")

    Local $tBuf = DllStructCreate("char buffer[" & $MAXGETHOSTSTRUCT & "]")
    Local $aRet = DllCall("ws2_32.dll", "HANDLE", "WSAAsyncGetHostByName", "HWND", $hGui, "UINT", $wMsg, "str", $sNodeName, "struct*", $tBuf, "int", $MAXGETHOSTSTRUCT)
    If $aRet[0] == 0 Then Return SetError(1, 0, 0)

    Local $IsInTime = False
    Local $iTimeStart = TimerInit()
    While 1
        If $WSAAsyncGetHostByName_lParam <> 0 Then
            $IsInTime = True
            ExitLoop
        EndIf
        Sleep(10)
        If $iTimeout > 0 And TimerDiff($iTimeStart) > $iTimeout Then ExitLoop
    WEnd
    If Not $IsInTime Then
        DllCall("ws2_32.dll", "int", "WSACancelAsyncRequest", "HANDLE", $aRet[0])
        $WSAAsyncGetHostByName_lParam = 0
        Return SetError(2, 0, 0)
    EndIf

    Local $WSAGETASYNCERROR = BitShift($WSAAsyncGetHostByName_lParam, 16)
    Local $WSAGETASYNCBUFLEN = BitAND($WSAAsyncGetHostByName_lParam, 0xFFFF)
    $WSAAsyncGetHostByName_lParam = 0
    If $WSAGETASYNCERROR Then Return SetError($WSAGETASYNCERROR, $WSAGETASYNCBUFLEN, 0)
    Local $sIP, $iIP, $tIPs

    Local $tHostent = DllStructCreate($tagHostent, DllStructGetPtr($tBuf))
    Local $ptrList = DllStructGetData($tHostent, "h_addr_list")
    If $ptrList = 0 Then Return SetError(3, 0, 0)

    Local $tAddressList = DllStructCreate("ptr", $ptrList)
    Local $firstAddr = DllStructGetData($tAddressList, 1)

    If DllStructGetData($tHostent, "h_addrtype") = $AF_INET Then
        $tIPs = DllStructCreate("UINT", DllStructGetData($tAddressList, 1))
        $iIP = DllStructGetData($tIPs, 1)
        If $iIP = 0 Then Return SetError(4, 0, 0)
        $sIP = _inet_ntoa($iIP)
    EndIf

    Return SetError(0, 0, $sIP)
EndFunc   ;==>_WSAAsyncGetHostByName_Timeout

Func _WSAAsyncGetHostByName_Callback($hWnd, $iMsgID, $wParam, $lParam)
    $WSAAsyncGetHostByName_lParam = $lParam
EndFunc   ;==>_WSAAsyncGetHostByName_Callback

Func _inet_ntoa($In_Addr) ;only IPv4 (deprecated)   --> use _inet_ntop() instead
    Local $aRet = DllCall("ws2_32.dll", "str", "inet_ntoa", "long", $In_Addr)
    Return $aRet[0]
EndFunc   ;==>_inet_ntoa

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

You are welcome. Glad to hear this.

Programming today is a race between software engineers striving to
build bigger and better idiot-proof programs, and the Universe
trying to produce bigger and better idiots.
So far, the Universe is winning.

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
 Share

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...