Jump to content

What's wrong with ping() (or with me)?


cherdeg
 Share

Recommended Posts

Hello Community,

Once again I don't understand...why would this function return fewer hosts as "online" as there are in reality? I have an array of 8 IPs which are all online on the LAN. Microsoft's ping returns every single one correctly as online. The function below returns only 3 of them - why?

#include <Constants.au3>
#include <Array.au3>


Local $s_MailRelayFQDN = "google.com"
;~ Local $s_MailRelayFQDN = "yahoo.com" ; try this instead...3 IPs
;~ Local $s_MailRelayFQDN = "microsoft.com" ; or this...2 IPs
;~ Local $s_MailRelayFQDN = "google.de" ; or this...3 IPs
;~ Local $s_MailRelayFQDN = "vmware.com" ; or this...1 IP
Local $a_IPs = _LookupIPs($s_MailRelayFQDN)
_ArrayDisplay($a_IPs)

$a_IPsChecked = _CheckOnlineStatus($a_IPs)
$a_OnlineIPs = $a_IPsChecked[0]
_ArrayDisplay($a_OnlineIPs)




; Function Name _LookupIPs()
; ==================================================================================================
;
; Function Name:    _LookupIPs()
;
; Description:      Gets the IPs of a given FQDN
;
; Parameter(s):     $s_FQDN
;
; Requirement(s):   AutoIt 3.2.10.0
;
; Return Value(s):  An array containing the IP(s) resolved for the given FQDN
;
; Author(s):        cs/IT solutions
;
; ==================================================================================================
Func _LookupIPs($s_FQDN)

    ; Setup and execute the command and fetch the STDout-data it produces
    $s_STDoutData = _RunReadStd("nslookup " & $s_FQDN, 0, @WorkingDir, 0, 1, @LF)
    ; Put the data to an array
    $a_tmp = StringSplit($s_STDoutData, @CRLF, 2)
    ; Delete the unneeded first 3 records
    For $i=1 To 3 
        _ArrayDelete($a_tmp, 0) 
    Next
    ; Add all records to a new string; remove the words "Address" or "Addresses"
    Local $s_tmp
    For $i=0 To UBound($a_tmp) -1
        $s_tmp &= StringReplace(StringReplace(StringStripWS($a_tmp[$i], 8), "Address:", ""), "Addresses:", "")
        If $i < UBound($a_tmp) -1 Then $s_tmp &= ","
    Next
    ; Split the string to an array
    $a_IPs = StringSplit($s_tmp, ",", 2)
    ; Return the array
    Return $a_IPs

EndFunc   ;==>_LookupIPs


; Function Name _CheckOnlineStatus()
; ==================================================================================================
;
; Function Name:    _CheckOnlineStatus()
;
; Description:      Checks if a host is online or not
;
; Parameter(s):     $a_Hostnames
;
; Requirement(s):   AutoIt 3.2.10.0
;
; Return Value(s):  Two arrays containing:
;                   a) the hostnames of the hosts that are online
;                   b) the hostnames of the hosts that are offline
;
; Author(s):        Manadar
;
; ==================================================================================================
Func _CheckOnlineStatus($a_Hostnames)

    ; Copy the array of hostnames to a temporary one (in a loop arrays are read-only <== This is not true)
    Local $a_tmpOnHosts[1]
    Local $a_tmpOffHosts[1]

    ; Loop reversely one by one through the original array of hostnames
    For $i_i = 0 To UBound($a_Hostnames) - 1
        ; Ping the current host to see if it is online
        ConsoleWrite("Ping: " & $a_Hostnames[$i_i] & @CRLF)
        $roundTrip = _Ping($a_Hostnames[$i_i])
        If @error Then
            ConsoleWrite("Offline" & @CRLF)
            ; It's offline, add it to a list of offline hosts
            _ArrayAdd($a_tmpOffHosts, $a_Hostnames[$i_i])
        Else
            ConsoleWrite("Online" & @CRLF)
            ; It's online, add it to a list of online hosts
            _ArrayAdd($a_tmpOnHosts, $a_Hostnames[$i_i])
        EndIf
    Next

    _ArrayDelete($a_tmpOnHosts, 0)
    _ArrayDelete($a_tmpOffHosts, 0)

    ; Save both the temporary arrays to a transport array...
    Local $a_Hosts[2]
    $a_Hosts[0] = $a_tmpOnHosts
    $a_Hosts[1] = $a_tmpOffHosts

    ; $a_tmpOnHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically
    ; $a_tmpOffHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically

    ; ...return the transport array back to main()
    Return $a_Hosts

EndFunc   ;==>_CheckOnlineStatus


; Function Name _Ping()
; ==================================================================================================
;
; Function Name:    _RunReadStd()
;
; Description:      Pings a specified host address or IP address with a set number attempts and 
;                   a set timeout
;
; Parameter(s):     $ipOrHostName, $numAttempts = 2, $timeOut = 100
;
; Requirement(s):   AutoIt 3.2.10.0
;
; Return Value(s):  Success: Returns the roundtrip (> 0)
;                   Failure: Returns 0 and sets @error to 1
;
; Author(s):        Manadar
;
; ==================================================================================================
Func _Ping($ipOrHostName, $numAttempts = 2, $timeOut = 100)
    
    For $attempt = 0 To $numAttempts
        $roundTrip = Ping($ipOrHostName, $timeOut)
        $err = @error

        ConsoleWrite("@error:" & $err & @CRLF & "ret: " & $roundTrip & @CRLF)

        If Not $err Then
            Return $roundTrip
        EndIf
    Next
    Return SetError(1, 0, 0)
    
EndFunc   ;==>_Ping


; Function Name _RunReadStd()
; ==================================================================================================
;
; Function Name:   _RunReadStd()
;
; Description::    Run a specified command, and return the Exitcode, StdOut text and
;                  StdErr text from from it. StdOut and StdErr are @tab delimited,
;                  with blank lines removed.
;
; Parameter(s):    $doscmd: the actual command to run, same as used with Run command
;                  $timeoutSeconds: maximum execution time in seconds, optional, default: 0 (wait forever),
;                  $workingdir: directory in which to execute $doscmd, optional, default: @ScriptDir
;                  $flag: show/hide flag, optional, default: @SW_HIDE
;                  $sDelim: stdOut and stdErr output deliminter, optional, default: @TAB
;                  $nRetVal: return single item from function instead of array, optional, default: -1 (return array)
;
; Requirement(s):  AutoIt 3.2.10.0
;
; Return Value(s): An array with three values, Exit Code, StdOut and StdErr
;
; Author(s):       lod3n
;                  (Thanks to mrRevoked for delimiter choice and non array return selection)
;                  (Thanks to mHZ for _ProcessOpenHandle() and _ProcessGetExitCode())
;                  (MetaThanks to DaveF for posting these DllCalls in Support Forum)
;                  (MetaThanks to JPM for including CloseHandle as needed)
;
; ==================================================================================================
Func _RunReadStd($doscmd, $timeoutSeconds = 0, $workingdir = @ScriptDir, $flag = @SW_HIDE, $nRetVal = -1, $sDelim = @TAB)
    
    Local $aReturn, $i_Pid, $h_Process, $i_ExitCode, $sStdOut, $sStdErr, $runTimer
    Dim $aReturn[3]

    ; run process with StdErr and StdOut flags
    $runTimer = TimerInit()
    $i_Pid = Run($doscmd, $workingdir, $flag, 6) ; 6 = $STDERR_CHILD+$STDOUT_CHILD

    ; Get process handle
    Sleep(100) ; or DllCall may fail - experimental
    $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid)

    ; create tab delimited string containing StdOut text from process
    $aReturn[1] = ""
    $sStdOut = ""
    While 1
        $sStdOut &= StdoutRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdOut = StringReplace($sStdOut, @CR, @TAB)
    $sStdOut = StringReplace($sStdOut, @LF, @TAB)
    $aStdOut = StringSplit($sStdOut, @TAB, 1)
    For $i = 1 To $aStdOut[0]
        $aStdOut[$i] = StringStripWS($aStdOut[$i], 3)
        If StringLen($aStdOut[$i]) > 0 Then
            $aReturn[1] &= $aStdOut[$i] & $sDelim
        EndIf
    Next
    $aReturn[1] = StringTrimRight($aReturn[1], 1)

    ; create tab delimited string containing StdErr text from process
    $aReturn[2] = ""
    $sStdErr = ""
    While 1
        $sStdErr &= StderrRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdErr = StringReplace($sStdErr, @CR, @TAB)
    $sStdErr = StringReplace($sStdErr, @LF, @TAB)
    $aStderr = StringSplit($sStdErr, @TAB, 1)
    For $i = 1 To $aStderr[0]
        $aStderr[$i] = StringStripWS($aStderr[$i], 3)
        If StringLen($aStderr[$i]) > 0 Then
            $aReturn[2] &= $aStderr[$i] & $sDelim
        EndIf
    Next
    $aReturn[2] = StringTrimRight($aReturn[2], 1)

    ; kill the process if it exceeds $timeoutSeconds
    If $timeoutSeconds > 0 Then
        If TimerDiff($runTimer) / 1000 > $timeoutSeconds Then
            ProcessClose($i_Pid)
        EndIf
    EndIf

    ; fetch exit code and close process handle
    If IsArray($h_Process) Then
        Sleep(100) ; or DllCall may fail - experimental
        $i_ExitCode = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', 0)
        If IsArray($i_ExitCode) Then
            $aReturn[0] = $i_ExitCode[2]
        Else
            $aReturn[0] = -1
        EndIf
        Sleep(100) ; or DllCall may fail - experimental
        DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process[0])
    Else
        $aReturn[0] = -2
    EndIf

    ; return single item if correctly specified with with $nRetVal
    If $nRetVal <> -1 And $nRetVal >= 0 And $nRetVal <= 2 Then Return $aReturn[$nRetVal]

    ; return array with exit code, stdout, and stderr
    Return $aReturn

EndFunc   ;==>_RunReadStd

Please help; I can't see any mistakes (maybe I'm blind by now).

Best Regards,

Chris

EDIT-1: Corrected the source to regard water's advice.

EDIT-2: Corrected the comments in the source to regard Manadar's advice.

EDIT-3: Replaced the source with the one from #7

Edited by cherdeg
Link to comment
Share on other sites

Because when a host can not be reached on the first try but on the second - then it is not added to $a_tmpOnHosts

My UDFs and Tutorials:

Spoiler

UDFs:
Active Directory (NEW 2022-02-19 - Version 1.6.1.0) - Download - General Help & Support - Example Scripts - Wiki
ExcelChart (2017-07-21 - Version 0.4.0.1) - Download - General Help & Support - Example Scripts
OutlookEX (2021-11-16 - Version 1.7.0.0) - Download - General Help & Support - Example Scripts - Wiki
OutlookEX_GUI (2021-04-13 - Version 1.4.0.0) - Download
Outlook Tools (2019-07-22 - Version 0.6.0.0) - Download - General Help & Support - Wiki
PowerPoint (2021-08-31 - Version 1.5.0.0) - Download - General Help & Support - Example Scripts - Wiki
Task Scheduler (NEW 2022-07-28 - Version 1.6.0.1) - Download - General Help & Support - Wiki

Standard UDFs:
Excel - Example Scripts - Wiki
Word - Wiki

Tutorials:
ADO - Wiki
WebDriver - Wiki

 

Link to comment
Share on other sites

Because when a host can not be reached on the first try but on the second - then it is not added to $a_tmpOnHosts

Okay, you made a point: I corrected that. But that does not seem to be causing the problem - I played with the timeout values and set all of them to 5000 and even higher. The result was exactly the same, 3 of 8 came back as online...

Again: Every single host in the list is pingable by Microsoft's ping.

Edited by cherdeg
Link to comment
Share on other sites

Your function seems to work fine, or I have accidentally fixed it while playing.

Note that you can't do this (this may be is probably going wrong):

Dim $a[1] = ["Hello world!!"]
Dim $b[1] = [$a]

MsgBox(0, "", $b[0][0]) ; FAILS!!

$c = $b[0]
MsgBox(0, "", $c[0])

; The function _CheckOnlineStatus() splits an array of hostnames or IPs into two arrays:
; One for the Online-Hosts, another for the Offline-Hosts.
; ==================================================================================================

#include <Array.au3>

Local $testIP[3] = ["127.0.0.1", "128.0.0.1", "129.0.0.1"]
$arr = _CheckOnlineStatus($testIP)

$online = $arr[0]
_ArrayDisplay($online)
$offline = $arr[1]
_ArrayDisplay($offline)

Func _CheckOnlineStatus($a_Hostnames)
    ; Copy the array of hostnames to a temporary one (in a loop arrays are read-only <== This is not true)
    Local $a_tmpOnHosts[1]
    Local $a_tmpOffHosts[1]
    
    ; Loop reversely one by one through the original array of hostnames
    For $i_i = 0 to UBound($a_Hostnames) -1
        ; Ping the current host to see if it is online
        $roundTrip = _Ping($a_Hostnames[$i_i])
        If @error Then
            ; It's offline, add it to a list of offline hosts
            _ArrayAdd($a_tmpOffHosts, $a_Hostnames[$i_i])
        Else
            ; It's online, add it to a list of online hosts
            _ArrayAdd($a_tmpOnHosts, $a_Hostnames[$i_i])
        EndIf
    Next
    
    _ArrayDelete($a_tmpOnHosts, 0)
    _ArrayDelete($a_tmpOffHosts, 0)
    
    ; Save both the temporary arrays to a transport array...
    Local $a_Hosts[2]
    $a_Hosts[0] = $a_tmpOnHosts
    $a_Hosts[1] = $a_tmpOffHosts
    
    ; $a_tmpOnHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically
    ; $a_tmpOffHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically
    
    ; ...return the transport array back to main()
    Return $a_Hosts

EndFunc   ;==>_CheckOnlineStatus

; Pings a specified host address or IP address with a set number attempts and a set timeout
; Success: Returns the roundtrip (> 0)
; Failure: Returns 0 and sets @error to 1

Func _Ping($ipOrHostName, $numAttempts = 2, $timeOut = 100)
    For $attempt = 0 to $numAttempts-1
        $roundTrip = Ping($ipOrHostName, $timeOut)
        If Not @error Then
            Return $roundTrip
        EndIf
    Next
    Return SetError(1, 0, 0)
EndFunc
Edited by Manadar
Link to comment
Share on other sites

Hey Manadar, sorry, but what are you talking of?

This works perfect.:

$a_Hosts[0] = $a_tmpOnHosts
$a_Hosts[1] = $a_tmpOffHosts
$a_tmpOnHosts = 0
$a_tmpOffHosts = 0
Return $a_Hosts

Both arrays are 1st copied to the "transport array", 2nd deleted and 3rd returned. Or why else would that (outside the function) work anyway?:

_ArrayDisplay($a_Hosts[0], "BLA")

Of course it is clear for me that MsgBox() can't display arrays. But that's not the point; logically the on-/off-arrays are extracted from the "transport array" before they are used further.

And, again of course: In a for...next loop not all arrays are read only. But the one the loop cycles through is.

Last but not least pinging three local IPs does not prove or invalidate anything.

Edited by cherdeg
Link to comment
Share on other sites

Nice job on misunderstanding me and then trying to start an argument. You officially qualify as an internet troll. Print a certificate, and lose the attitude.

Now that's out of the way...

This works perfect.:

$a_Hosts[0] = $a_tmpOnHosts
$a_Hosts[1] = $a_tmpOffHosts
$a_tmpOnHosts = 0
$a_tmpOffHosts = 0
Return $a_Hosts

Both arrays are 1st copied to the "transport array", 2nd deleted and 3rd returned. Or why else would that (outside the function) work anyway?:

_ArrayDisplay($a_Hosts[0], "BLA")

All I said was that you don't have to destroy a variable that holds an array by assigning 0 to it. Once a local variable leaves the current scope, they are destroyed automatically. It's not necessary to delete an array by assigning it 0, in this case.

Of course it is clear for me that MsgBox() can't display arrays. But that's not the point; logically the on-/off-arrays are extracted from the "transport array" before they are used further.

In this example:

Dim $a[1] = ["Hello world!!"]
Dim $b[1] = [$a]

MsgBox(0, "", $b[0][0]) ; FAILS!!

In some languages, the variable $b would be a two dimensional array. If that's the case you can retrieve the element by doing [0][0], this is something AutoIt doesn't support: But a lot of other languages do. Since you have failed to provide a fully functional reproduction script, I have to guess at some parts which may be going wrong, this was one of them.

And, again of course: In a for...next loop not all arrays are read only. But the one the loop cycles through is.

Oh?

Local $a[3] = [1, 2, 3]
Local $b[3] = [4, 5, 6]

; Array is 1 2 3

For $i = 0 to 2
    MsgBox(0, "", $a[$i])
Next

For $i = 0 to 2
    $a[$i] = 4 - $a[$i]
Next

; Array is now 3 2 1

For $i = 0 to 2
    MsgBox(0, "", $a[$i])
Next

For $i = 0 to 2
    $a = $b ; just an example
Next

; Array is now 4 5 6

For $i = 0 to 2
    MsgBox(0, "", $a[$i])
Next

Last but not least pinging three local IPs does not prove or invalidate anything.

It proves that the rest of the code is fine, and that you can focus on analyzing the functionality of "Ping". This is an important fact to establish, because now you can write a reproducer as simple as:

$ret = Ping("123.123.123.123")
ConsoleWrite("@error: " & @error & @CRLF & "Ret: " & $ret & @CRLF)

Since this works as expected, you might have another look at your original script (which also works).

I have extended the working example with some debugging:

; The function _CheckOnlineStatus() splits an array of hostnames or IPs into two arrays:
; One for the Online-Hosts, another for the Offline-Hosts.
; ==================================================================================================

#include <Array.au3>

Local $testIP[4] = ["www.google.com", "www.microsoft.com", "www.msn.com", "123.123.123.123"]
$arr = _CheckOnlineStatus($testIP)

$online = $arr[0]
_ArrayDisplay($online, "Online")
$offline = $arr[1]
_ArrayDisplay($offline, "Offline")

Func _CheckOnlineStatus($a_Hostnames)
    ; Copy the array of hostnames to a temporary one (in a loop arrays are read-only <== This is not true)
    Local $a_tmpOnHosts[1]
    Local $a_tmpOffHosts[1]
    
    ; Loop reversely one by one through the original array of hostnames
    For $i_i = 0 to UBound($a_Hostnames) -1
        ; Ping the current host to see if it is online
        ConsoleWrite("Ping: " & $a_Hostnames[$i_i] & @CRLF)
        $roundTrip = _Ping($a_Hostnames[$i_i])
        If @error Then
            ConsoleWrite("Offline" & @CRLF)
            ; It's offline, add it to a list of offline hosts
            _ArrayAdd($a_tmpOffHosts, $a_Hostnames[$i_i])
        Else
            ConsoleWrite("Online" & @CRLF)
            ; It's online, add it to a list of online hosts
            _ArrayAdd($a_tmpOnHosts, $a_Hostnames[$i_i])
        EndIf
    Next
    
    _ArrayDelete($a_tmpOnHosts, 0)
    _ArrayDelete($a_tmpOffHosts, 0)
    
    ; Save both the temporary arrays to a transport array...
    Local $a_Hosts[2]
    $a_Hosts[0] = $a_tmpOnHosts
    $a_Hosts[1] = $a_tmpOffHosts
    
    ; $a_tmpOnHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically
    ; $a_tmpOffHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically
    
    ; ...return the transport array back to main()
    Return $a_Hosts

EndFunc   ;==>_CheckOnlineStatus

; Pings a specified host address or IP address with a set number attempts and a set timeout
; Success: Returns the roundtrip (> 0)
; Failure: Returns 0 and sets @error to 1
Func _Ping($ipOrHostName, $numAttempts = 2, $timeOut = 100)
    For $attempt = 0 to $numAttempts
        $roundTrip = Ping($ipOrHostName, $timeOut)
        $err = @error
        
        ConsoleWrite("@error:" & $err & @CRLF & "ret: " & $roundTrip & @CRLF)
        
        If Not $err Then
            Return $roundTrip
        EndIf
    Next
    Return SetError(1, 0, 0)
EndFunc
Link to comment
Share on other sites

Nice job on misunderstanding me and then trying to start an argument. You officially qualify as an internet troll. Print a certificate, and lose the attitude.

Thanks for the flowers. You made me cry. Probably you screwed up my whole weekend, I'll need weeks to recover from that. I hope you can live with that. :)

From the helpfile ("Dim"):

To erase an array (maybe because it is a large global array and you want to free the memory), simply assign a single value to it:

$array = 0

This will free the array and convert it back to the single value of 0.

Probably I should add to my sig that I am no programmer at all and use AutoIt for about a year (for phun, not as a pro). So basically I don't think about scopes of variables if I don't need to, please excuse that slothfulness. I just do what's in the helpfile. If my code is not perfect but works the way I need it to, I'm quite comfortable with that.

From the helpfile ("For...In...Next"):

Autoit Array's are read-only when using For...In. While you can assign the variable inside the For...In loop a value, this change is not reflected in the array itself. To modify the contents of an array during enumeration use a For...To loop.

Yes, I know. I don't use a For...In...Next-loop. But I did in an earlier version of the function. Currently I am quite ill and can't concentrate as usual and forgot about it. So basically both our statements contain...something.

This:

Dim $a[1] = ["Hello world!!"]
Dim $b[1] = [$a]
MsgBox(0, "", $b[0][0]) ; FAILS!!
...never was a question in doubt. I well know that $b[1] nests array $a.

So the code below is my whole script in its current state (please note that I've copied the code from your last post without modifying anything):

#include <Constants.au3>
#include <Array.au3>


Local $s_MailRelayFQDN = "google.com"
;~ Local $s_MailRelayFQDN = "yahoo.com" ; try this instead...3 IPs
;~ Local $s_MailRelayFQDN = "microsoft.com" ; or this...2 IPs
;~ Local $s_MailRelayFQDN = "google.de" ; or this...3 IPs
;~ Local $s_MailRelayFQDN = "vmware.com" ; or this...1 IP
Local $a_IPs = _LookupIPs($s_MailRelayFQDN)
_ArrayDisplay($a_IPs)

$a_IPsChecked = _CheckOnlineStatus($a_IPs)
$a_OnlineIPs = $a_IPsChecked[0]
_ArrayDisplay($a_OnlineIPs)




; Function Name _LookupIPs()
; ==================================================================================================
;
; Function Name:    _LookupIPs()
;
; Description:      Gets the IPs of a given FQDN
;
; Parameter(s):     $s_FQDN
;
; Requirement(s):   AutoIt 3.2.10.0
;
; Return Value(s):  An array containing the IP(s) resolved for the given FQDN
;
; Author(s):        cs/IT solutions
;
; ==================================================================================================
Func _LookupIPs($s_FQDN)

    ; Setup and execute the command and fetch the STDout-data it produces
    $s_STDoutData = _RunReadStd("nslookup " & $s_FQDN, 0, @WorkingDir, 0, 1, @LF)
    ; Put the data to an array
    $a_tmp = StringSplit($s_STDoutData, @CRLF, 2)
    ; Delete the unneeded first 3 records
    For $i=1 To 3 
        _ArrayDelete($a_tmp, 0) 
    Next
    ; Add all records to a new string; remove the words "Address" or "Addresses"
    Local $s_tmp
    For $i=0 To UBound($a_tmp) -1
        $s_tmp &= StringReplace(StringReplace(StringStripWS($a_tmp[$i], 8), "Address:", ""), "Addresses:", "")
        If $i < UBound($a_tmp) -1 Then $s_tmp &= ","
    Next
    ; Split the string to an array
    $a_IPs = StringSplit($s_tmp, ",", 2)
    ; Return the array
    Return $a_IPs

EndFunc   ;==>_LookupIPs


; Function Name _CheckOnlineStatus()
; ==================================================================================================
;
; Function Name:    _CheckOnlineStatus()
;
; Description:      Checks if a host is online or not
;
; Parameter(s):     $a_Hostnames
;
; Requirement(s):   AutoIt 3.2.10.0
;
; Return Value(s):  Two arrays containing:
;                   a) the hostnames of the hosts that are online
;                   b) the hostnames of the hosts that are offline
;
; Author(s):        Manadar
;
; ==================================================================================================
Func _CheckOnlineStatus($a_Hostnames)

    ; Copy the array of hostnames to a temporary one (in a loop arrays are read-only <== This is not true)
    Local $a_tmpOnHosts[1]
    Local $a_tmpOffHosts[1]

    ; Loop reversely one by one through the original array of hostnames
    For $i_i = 0 To UBound($a_Hostnames) - 1
        ; Ping the current host to see if it is online
        ConsoleWrite("Ping: " & $a_Hostnames[$i_i] & @CRLF)
        $roundTrip = _Ping($a_Hostnames[$i_i])
        If @error Then
            ConsoleWrite("Offline" & @CRLF)
            ; It's offline, add it to a list of offline hosts
            _ArrayAdd($a_tmpOffHosts, $a_Hostnames[$i_i])
        Else
            ConsoleWrite("Online" & @CRLF)
            ; It's online, add it to a list of online hosts
            _ArrayAdd($a_tmpOnHosts, $a_Hostnames[$i_i])
        EndIf
    Next

    _ArrayDelete($a_tmpOnHosts, 0)
    _ArrayDelete($a_tmpOffHosts, 0)

    ; Save both the temporary arrays to a transport array...
    Local $a_Hosts[2]
    $a_Hosts[0] = $a_tmpOnHosts
    $a_Hosts[1] = $a_tmpOffHosts

    ; $a_tmpOnHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically
    ; $a_tmpOffHosts = 0 <== When these fall out of the current scope (EndFunc) they are destroyed automatically

    ; ...return the transport array back to main()
    Return $a_Hosts

EndFunc   ;==>_CheckOnlineStatus


; Function Name _Ping()
; ==================================================================================================
;
; Function Name:    _RunReadStd()
;
; Description:      Pings a specified host address or IP address with a set number attempts and 
;                   a set timeout
;
; Parameter(s):     $ipOrHostName, $numAttempts = 2, $timeOut = 100
;
; Requirement(s):   AutoIt 3.2.10.0
;
; Return Value(s):  Success: Returns the roundtrip (> 0)
;                   Failure: Returns 0 and sets @error to 1
;
; Author(s):        Manadar
;
; ==================================================================================================
Func _Ping($ipOrHostName, $numAttempts = 2, $timeOut = 100)
    
    For $attempt = 0 To $numAttempts
        $roundTrip = Ping($ipOrHostName, $timeOut)
        $err = @error

        ConsoleWrite("@error:" & $err & @CRLF & "ret: " & $roundTrip & @CRLF)

        If Not $err Then
            Return $roundTrip
        EndIf
    Next
    Return SetError(1, 0, 0)
    
EndFunc   ;==>_Ping


; Function Name _RunReadStd()
; ==================================================================================================
;
; Function Name:   _RunReadStd()
;
; Description::    Run a specified command, and return the Exitcode, StdOut text and
;                  StdErr text from from it. StdOut and StdErr are @tab delimited,
;                  with blank lines removed.
;
; Parameter(s):    $doscmd: the actual command to run, same as used with Run command
;                  $timeoutSeconds: maximum execution time in seconds, optional, default: 0 (wait forever),
;                  $workingdir: directory in which to execute $doscmd, optional, default: @ScriptDir
;                  $flag: show/hide flag, optional, default: @SW_HIDE
;                  $sDelim: stdOut and stdErr output deliminter, optional, default: @TAB
;                  $nRetVal: return single item from function instead of array, optional, default: -1 (return array)
;
; Requirement(s):  AutoIt 3.2.10.0
;
; Return Value(s): An array with three values, Exit Code, StdOut and StdErr
;
; Author(s):       lod3n
;                  (Thanks to mrRevoked for delimiter choice and non array return selection)
;                  (Thanks to mHZ for _ProcessOpenHandle() and _ProcessGetExitCode())
;                  (MetaThanks to DaveF for posting these DllCalls in Support Forum)
;                  (MetaThanks to JPM for including CloseHandle as needed)
;
; ==================================================================================================
Func _RunReadStd($doscmd, $timeoutSeconds = 0, $workingdir = @ScriptDir, $flag = @SW_HIDE, $nRetVal = -1, $sDelim = @TAB)
    
    Local $aReturn, $i_Pid, $h_Process, $i_ExitCode, $sStdOut, $sStdErr, $runTimer
    Dim $aReturn[3]

    ; run process with StdErr and StdOut flags
    $runTimer = TimerInit()
    $i_Pid = Run($doscmd, $workingdir, $flag, 6) ; 6 = $STDERR_CHILD+$STDOUT_CHILD

    ; Get process handle
    Sleep(100) ; or DllCall may fail - experimental
    $h_Process = DllCall('kernel32.dll', 'ptr', 'OpenProcess', 'int', 0x400, 'int', 0, 'int', $i_Pid)

    ; create tab delimited string containing StdOut text from process
    $aReturn[1] = ""
    $sStdOut = ""
    While 1
        $sStdOut &= StdoutRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdOut = StringReplace($sStdOut, @CR, @TAB)
    $sStdOut = StringReplace($sStdOut, @LF, @TAB)
    $aStdOut = StringSplit($sStdOut, @TAB, 1)
    For $i = 1 To $aStdOut[0]
        $aStdOut[$i] = StringStripWS($aStdOut[$i], 3)
        If StringLen($aStdOut[$i]) > 0 Then
            $aReturn[1] &= $aStdOut[$i] & $sDelim
        EndIf
    Next
    $aReturn[1] = StringTrimRight($aReturn[1], 1)

    ; create tab delimited string containing StdErr text from process
    $aReturn[2] = ""
    $sStdErr = ""
    While 1
        $sStdErr &= StderrRead($i_Pid)
        If @error Then ExitLoop
    WEnd
    $sStdErr = StringReplace($sStdErr, @CR, @TAB)
    $sStdErr = StringReplace($sStdErr, @LF, @TAB)
    $aStderr = StringSplit($sStdErr, @TAB, 1)
    For $i = 1 To $aStderr[0]
        $aStderr[$i] = StringStripWS($aStderr[$i], 3)
        If StringLen($aStderr[$i]) > 0 Then
            $aReturn[2] &= $aStderr[$i] & $sDelim
        EndIf
    Next
    $aReturn[2] = StringTrimRight($aReturn[2], 1)

    ; kill the process if it exceeds $timeoutSeconds
    If $timeoutSeconds > 0 Then
        If TimerDiff($runTimer) / 1000 > $timeoutSeconds Then
            ProcessClose($i_Pid)
        EndIf
    EndIf

    ; fetch exit code and close process handle
    If IsArray($h_Process) Then
        Sleep(100) ; or DllCall may fail - experimental
        $i_ExitCode = DllCall('kernel32.dll', 'ptr', 'GetExitCodeProcess', 'ptr', $h_Process[0], 'int*', 0)
        If IsArray($i_ExitCode) Then
            $aReturn[0] = $i_ExitCode[2]
        Else
            $aReturn[0] = -1
        EndIf
        Sleep(100) ; or DllCall may fail - experimental
        DllCall('kernel32.dll', 'ptr', 'CloseHandle', 'ptr', $h_Process[0])
    Else
        $aReturn[0] = -2
    EndIf

    ; return single item if correctly specified with with $nRetVal
    If $nRetVal <> -1 And $nRetVal >= 0 And $nRetVal <= 2 Then Return $aReturn[$nRetVal]

    ; return array with exit code, stdout, and stderr
    Return $aReturn

EndFunc   ;==>_RunReadStd

Result: I can ping all the IPs (external and internal targets) if I use Microsoft's ping from my XP system's command line. If I use the script, I today get 4 of 8 hosts for my internal FQDN, which, at least, is an improvement to the yesterday's 3. But I doubt it has something to do with your/my code. For the external hosts as google.com I sometimes get one pingable host but most times it states that none was online.

What now?

Edited by cherdeg
Link to comment
Share on other sites

Hello,

aahhh...I hoped so much that I'd return to office this morning and find sombody's perfect solution in this thread...'coz my problem still exists and I still lack of ideas how to start solving it. The code so far seems okay for me, but in my opinion AutoIt's ping() does not work as supposed.

Best Regards,

Chris

Link to comment
Share on other sites

Working fine to me!

I added some internet hosts and corporate hosts, mixing unc and ip and all running smoothly!

Check you DNS/host file.

Cheers

Old Scriptology

Visual Ping 1.8 - Mass Ping Program with export to txt delimited.

Desktop 2 RGB and YMCK - Pick a color in the desktop and get the RGB and YMCK code.

Desktop 2 RGB - Pick a color in the desktop and get the RGB code.

ShootIT 1.0 - Screen Capture full and partial screen

[font="'Arial Black';"]Remember Remember The Fifth of November.[/font]

Link to comment
Share on other sites

Check you DNS/host file.

Don't need to. You wonder why?

Because I believe I wrote about 3 times in this thread, that I can ping all the host-IPs nslookup returns from the Windows command line without any problem. I emphasized the statements in my above posts for you. Only AutoIt's ping() is not able to see them online. That is the reason for this thread.

Is this simple fact that hard to understand?

Edited by cherdeg
Link to comment
Share on other sites

NSLOOKUP IS NOT PING

try ping from your command prompt, this should work the same way as ping in AutoIt :)

Edit:

There are servers who block ping-requests, but are still online. This is not the fault of AutoIt, but the configuration of the servers you want to ping.

Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

NSLOOKUP IS NOT PING

try ping from your command prompt, this should work the same way as ping in AutoIt :)

Edit:

There are servers who block ping-requests, but are still online. This is not the fault of AutoIt, but the configuration of the servers you want to ping.

You also can't read, hmmm?

And, before posting, you don't drop even a quick look at the sources you're going to write about, hmmm?

Would you please just try to assume that not everybody is a 12 year old girl (probably even most of them would know that nslookup is not ping)?

I mean, hey, WTF? I use nslookup to get the IPs of certain FQDNs. In case of "google.com" the IPs 74.125.45.100, 74.125.53.100, 74.125.67.100 are returned (at least from my location). Pinging these IPs one after the other from command line shows that every single host is online. If I set $s_MailRelayFQDN to "google.com", the returned array contains exactly these IPs. Manadar's function "_Ping" which uses AutoIt's ping() returns all hosts as offline; I have the same result with all my tries.

Edited by cherdeg
Link to comment
Share on other sites

You have quite a problem on your hands, which I can understand explains for the attitude. It's still not a very nice attitude when you're coming asking for help.

Can you try the script on another machine?

Try installing the latest AutoIt, etc.

I believe for everyone who have tried this it is working as expected, except yourself..

Also try writing a small reproducer and try it on several machines: (Change the address to one that fails, which you are expecting to succeed)

$a = Ping("10.10.10.10")
ConsoleWrite($a & @CRLF & @error & @CRLF)
Edited by Manadar
Link to comment
Share on other sites

You also can't read, hmmm?

And, before posting, you don't drop even a quick look at the sources you're going to write about, hmmm?

Oh, sorry, i misunderstood you underlined text. I read a full stop between host-IPs and nslookup. Edited by ProgAndy

*GERMAN* [note: you are not allowed to remove author / modified info from my UDFs]My UDFs:[_SetImageBinaryToCtrl] [_TaskDialog] [AutoItObject] [Animated GIF (GDI+)] [ClipPut for Image] [FreeImage] [GDI32 UDFs] [GDIPlus Progressbar] [Hotkey-Selector] [Multiline Inputbox] [MySQL without ODBC] [RichEdit UDFs] [SpeechAPI Example] [WinHTTP]UDFs included in AutoIt: FTP_Ex (as FTPEx), _WinAPI_SetLayeredWindowAttributes

Link to comment
Share on other sites

the attitude

Yeah, I'm quite irritated by now. I think the least one can await from any guy willing to help is that he reads before he posts completely unqualified comments only wasting everybody's time.

You and I, we had some misunderstandings, but I can see you're really trying to help - thank you for that!

Okay, so I compiled my source as as cli app and tested it on four systems. On each the Windows firewall is off and there is no additional firewall installed. The script is compiled with the latest version of AutoIT (v3.3.0.0). The results are the same on every machine:

Ping: 74.125.45.100
@error:1
ret: 0
@error:1
ret: 0
@error:1
ret: 0
Offline
Ping: 74.125.53.100
@error:1
ret: 0
@error:1
ret: 0
@error:1
ret: 0
Offline
Ping: 74.125.67.100
@error:1
ret: 0
@error:1
ret: 0
@error:1
ret: 0
Offline

I don't want to look as ignorant as others, so I also tried your two lines of code on the same machines. I modified them a bit, which shouldn't impact the basic funtionality (the IPs belong to google.com):

#AutoIt3Wrapper_Change2CUI=y
local $array[3] = ["74.125.45.100", "74.125.53.100", "74.125.67.100"]
for $i=0 to UBound($array) -1
    $a = ping($array[$i])
    consolewrite("Return-Value: " & $a & @CRLF & "@Error-Value: " & @error & @CRLF)
next

The result is, again, the same:

Return-Value: 0
@Error-Value: 1
Return-Value: 0
@Error-Value: 1
Return-Value: 0
@Error-Value: 1

And last but not least: all IPs are still pingable from all hosts' command line (Microsoft's ping).

Edited by cherdeg
Link to comment
Share on other sites

I still have the same problem. Please again note that on four source-hosts everything is WORKING with Microsofts ping and NOT WORKING with AutoITs ping().

On none of the systems any kind of firewall or antivirus software is installed. A misconfiguration of the source hosts

The problem clearly comes from AutoITs ping() function which reports hosts that are online as offline (Return 0, @error 1). Please prove me wrong.

Link to comment
Share on other sites

I still have the same problem. Please again note that on four source-hosts everything is WORKING with Microsofts ping and NOT WORKING with AutoITs ping().

On none of the systems any kind of firewall or antivirus software is installed. A misconfiguration of the source hosts

The problem clearly comes from AutoITs ping() function which reports hosts that are online as offline (Return 0, @error 1). Please prove me wrong.

The only way we can prove you are wrong is by showing that it works, which it does, for everyone else at least. You're a special case.

The simple solution would be to run the Microsoft ping command, and parse the outputs from command line.

Some pointers:

Run

StdoutRead

StringRegexp

etc.

Edited by Manadar
Link to comment
Share on other sites

Hi Manadar,

so you tell me that this:

#AutoIt3Wrapper_Change2CUI=y
local $array[3] = ["74.125.45.100", "74.125.53.100", "74.125.67.100"]
for $i=0 to UBound($array) -1
    $a = ping($array[$i])
    consolewrite("IP          : " & $array[$i] & @CRLF & "Return-Value: " & $a & @CRLF & "@Error-Value: " & @error & @CRLF & @CRLF)
next

...returns three online hosts on your machine?

You can see my result if you check the attached screenshot (hey, today one of the google.com's frontend hosts really is offline!). What could be a reason for this behaviour?

I really need to use AutoIT's ping() due to the fact that Microsoft's counterpart is way to slow. I need to check about 400 hosts in acceptable time...so it would be really great to get that working.

post-35371-12567320228822_thumb.png

Edited by cherdeg
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...