-
Notifications
You must be signed in to change notification settings - Fork 72
/
Copy pathping_by_Uberi.ahk
348 lines (296 loc) · 13.9 KB
/
ping_by_Uberi.ahk
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#NoEnv
/*
SimplePing
==========
AHK library providing a variety of ICMP pinging-related functionality.
Examples
--------
Ping a Google DNS server:
MsgBox % "Round trip time: " . RoundTripTime("8.8.8.8")
Ping two different Google DNS servers at the same time:
Addresses := ["8.8.8.8", "8.8.4.4"]
Value := ""
For Index, PingTime In RoundTripTimeList(Addresses)
Value .= "Server: "List[Index] . ", Round trip time: " . PingTime . "ms`n"
MsgBox %Value%
Send an ICMP request to a Google DNS server:
MsgBox % "Round trip time: " . Ping("8.8.8.8") . "ms"
Ping example.com with some data and show the response (the SubStr causes the result to be interpreted as a string):
MsgBox % "Round trip time: " . Ping("192.0.43.10",800,"Hello!",6,Value,Length) . "ms, Response: " . SubStr(Value,1)
Overview
--------
All functions throw exceptions on failure.
### RTT := Ping(Address,Timeout = 800,ByRef Data = "",Length = 0,ByRef Result = "",ByRef ResultLength = 0)
Pings an address and waits for a response.
Useful for sending custom pings supporting messages and responses.
### RTT := PingAsync(Address,Timeout = 800,ByRef Data = "",Length = 0,ByRef Result = "",ByRef ResultLength = 0)
Works exactly the same as Ping(), but uses an asynchronous event-based method.
Intended only as a technology demo, avoid using as it may change or be removed in the future.
### RTT := RoundTripTime(Address,Timeout = 800)
Determines the round trip time (sometimes called the "ping") from the local machine to the address.
Useful for pinging a server to determine latency.
### RTT := RoundTripTimeList(AddressList,Timeout = 800)
Determines the round trip time (sometimes called the "ping") from the local machine to a list of 64 or fewer addresses.
Useful for quickly pinging an entire server list to find the amount of latency in the connection to each.
Parameters
----------
RTT: The round trip time in milliseconds (e.g., 76). If unknown or timed out, this value is -1.
Address: IPv4 address as a string in dotted number format (e.g., "127.0.0.1").
AddressList: Array of IPv4 addresses as strings in dotted number format (e.g., ["127.0.0.1", "8.8.4.4"]).
Timeout: How long the function should wait, in milliseconds, before giving an error (e.g., 400).
Data: The data to send with the ping (e.g., "Hello"). Can be binary data as well.
Length: The length of the data to send with the ping (e.g., 5).
Result: The data in the response to the ping (e.g., "Salutations"). Can be binary data as well.
ResultLength: The length of the data in the response to the ping (e.g., 11).
*/
Ping(Address,Timeout = 800,ByRef Data = "",Length = 0,ByRef Result = "",ByRef ResultLength = 0)
{
If DllCall("LoadLibrary","Str","ws2_32","UPtr") = 0 ;NULL
throw Exception("Could not load WinSock 2 library.")
If DllCall("LoadLibrary","Str","icmp","UPtr") = 0 ;NULL
throw Exception("Could not load ICMP library.")
NumericAddress := DllCall("ws2_32\inet_addr","AStr",Address,"UInt")
If NumericAddress = 0xFFFFFFFF ;INADDR_NONE
throw Exception("Could not convert IP address string to numeric format.")
hPort := DllCall("icmp\IcmpCreateFile","UPtr") ;open port
If hPort = -1 ;INVALID_HANDLE_VALUE
throw Exception("Could not open port.")
StructLength := 270 + (A_PtrSize * 2) ;ICMP_ECHO_REPLY structure
VarSetCapacity(Reply,StructLength)
Count := DllCall("icmp\IcmpSendEcho"
,"UPtr",hPort ;ICMP handle
,"UInt",NumericAddress ;IP address
,"UPtr",&Data ;request data
,"UShort",Length ;length of request data
,"UPtr",0 ;pointer to IP options structure
,"UPtr",&Reply ;reply buffer
,"UInt",StructLength ;length of reply buffer
,"UInt",Timeout) ;ping timeout
If NumGet(Reply,4,"UInt") = 11001 ;IP_BUF_TOO_SMALL
{
StructLength *= Count
VarSetCapacity(Reply,StructLength)
DllCall("icmp\IcmpSendEcho"
,"UPtr",hPort ;ICMP handle
,"UInt",NumericAddress ;IP address
,"UPtr",&Data ;request data
,"UShort",Length ;length of request data
,"UPtr",0 ;pointer to IP options structure
,"UPtr",&Reply ;reply buffer
,"UInt",StructLength ;length of reply buffer
,"UInt",Timeout) ;ping timeout
}
If !DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not close port.")
If Status In 11002,11003,11004,11005,11010 ;IP_DEST_NET_UNREACHABLE, IP_DEST_HOST_UNREACHABLE, IP_DEST_PROT_UNREACHABLE, IP_DEST_PORT_UNREACHABLE, IP_REQ_TIMED_OUT
{
VarSetCapacity(Result,0)
Return, -1
}
If NumGet(Reply,4,"UInt") != 0 ;IP_SUCCESS
throw Exception("Could not send echo.")
ResultLength := NumGet(Reply,12,"UShort")
VarSetCapacity(Result,ResultLength)
DllCall("RtlMoveMemory","UPtr",&Result,"UPtr",NumGet(Reply,16),"UPtr",ResultLength)
Return, NumGet(Reply,8,"UInt")
}
PingAsync(Address,Timeout = 800,ByRef Data = "",Length = 0,ByRef Result = "",ByRef ResultLength = 0)
{
If DllCall("LoadLibrary","Str","ws2_32","UPtr") = 0 ;NULL
throw Exception("Could not load WinSock 2 library.")
If DllCall("LoadLibrary","Str","icmp","UPtr") = 0 ;NULL
throw Exception("Could not load ICMP library.")
hPort := DllCall("icmp\IcmpCreateFile","UPtr") ;open port
If hPort = -1 ;INVALID_HANDLE_VALUE
throw Exception("Could not open port.")
hEvent := DllCall("CreateEvent"
,"UPtr",0 ;security attributes structure
,"UInt",True ;manual reset event
,"UInt",False ;initially not signalled
,"UPtr",0 ;event name
,"UPtr")
If !hEvent
{
DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not create event.")
}
NumericAddress := DllCall("ws2_32\inet_addr","AStr",Address,"UInt")
If NumericAddress = 0xFFFFFFFF ;INADDR_NONE
throw Exception("Could not convert IP address string to numeric format.")
StructLength := 250 + 20 + (A_PtrSize * 2) ;ICMP_ECHO_REPLY structure
VarSetCapacity(Reply,StructLength)
DllCall("icmp\IcmpSendEcho2"
,"UPtr",hPort ;ICMP handle
,"UPtr",hEvent ;event handle
,"UPtr",0 ;APC routine handle
,"UPtr",0 ;APC routine context
,"UInt",NumericAddress ;IP address
,"UPtr",&Data ;request data
,"UShort",Length ;length of request data
,"UPtr",0 ;pointer to IP options structure
,"UPtr",&Reply ;reply buffer
,"UInt",StructLength ;length of reply buffer
,"UInt",Timeout) ;ping timeout
If A_LastError != 0x3E5 ;ERROR_IO_PENDING
{
DllCall("CloseHandle","UPtr",hEvent) ;close event
DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not send echo.")
}
If DllCall("WaitForSingleObject","UPtr",hEvent,"UInt",Timeout) != 0 ;WAIT_OBJECT_0
{
DllCall("CloseHandle","UPtr",hEvent) ;close event
DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not detect ping completion.")
}
Status := NumGet(Reply,4,"UInt")
If Status = 11001 ;IP_BUF_TOO_SMALL
{
StructLength *= Count
VarSetCapacity(Reply,StructLength)
DllCall("icmp\IcmpSendEcho"
,"UPtr",hPort ;ICMP handle
,"UInt",NumericAddress ;IP address
,"UPtr",&Data ;request data
,"UShort",Length ;length of request data
,"UPtr",0 ;pointer to IP options structure
,"UPtr",&Reply ;reply buffer
,"UInt",StructLength ;length of reply buffer
,"UInt",Timeout) ;ping timeout
If A_LastError != 0x3E5 ;ERROR_IO_PENDING
{
DllCall("CloseHandle","UPtr",hEvent) ;close event
DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not send echo.")
}
If DllCall("WaitForSingleObject","UPtr",hEvent,"UInt",Timeout) != 0 ;WAIT_OBJECT_0
{
DllCall("CloseHandle","UPtr",hEvent) ;close event
DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not detect ping completion.")
}
Status := NumGet(Reply,4,"UInt")
}
If !DllCall("CloseHandle","UPtr",hEvent) ;close event
throw Exception("Could not close event.")
If !DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not close port.")
If Status In 11002,11003,11004,11005,11010 ;IP_DEST_NET_UNREACHABLE, IP_DEST_HOST_UNREACHABLE, IP_DEST_PROT_UNREACHABLE, IP_DEST_PORT_UNREACHABLE, IP_REQ_TIMED_OUT
{
VarSetCapacity(Result,0)
Return, -1
}
If Status != 0 ;IP_SUCCESS
throw Exception("Could not retrieve echo response.")
ResultLength := NumGet(Reply,12,"UShort")
VarSetCapacity(Result,ResultLength)
DllCall("RtlMoveMemory","UPtr",&Result,"UPtr",NumGet(Reply,16),"UPtr",ResultLength)
Return, NumGet(Reply,8,"UInt")
}
RoundTripTime(Address,Timeout = 800)
{
If DllCall("LoadLibrary","Str","ws2_32","UPtr") = 0 ;NULL
throw Exception("Could not load WinSock 2 library.")
If DllCall("LoadLibrary","Str","icmp","UPtr") = 0 ;NULL
throw Exception("Could not load ICMP library.")
NumericAddress := DllCall("ws2_32\inet_addr","AStr",Address,"UInt")
If NumericAddress = 0xFFFFFFFF ;INADDR_NONE
throw Exception("Could not convert IP address string to numeric format.")
hPort := DllCall("icmp\IcmpCreateFile","UPtr") ;open port
If hPort = -1 ;INVALID_HANDLE_VALUE
throw Exception("Could not open port.")
StructLength := 270 + (A_PtrSize * 2) ;ICMP_ECHO_REPLY structure
VarSetCapacity(Reply,StructLength)
Count := DllCall("icmp\IcmpSendEcho"
,"UPtr",hPort ;ICMP handle
,"UInt",NumericAddress ;IP address
,"Str","" ;request data
,"UShort",0 ;length of request data
,"UPtr",0 ;pointer to IP options structure
,"UPtr",&Reply ;reply buffer
,"UInt",StructLength ;length of reply buffer
,"UInt",Timeout) ;ping timeout
If !DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not close port.")
Status := NumGet(Reply,4,"UInt")
If Status In 11002,11003,11004,11005,11010 ;IP_DEST_NET_UNREACHABLE, IP_DEST_HOST_UNREACHABLE, IP_DEST_PROT_UNREACHABLE, IP_DEST_PORT_UNREACHABLE, IP_REQ_TIMED_OUT
{
VarSetCapacity(Result,0)
Return, -1
}
If Status != 0 ;IP_SUCCESS
throw Exception("Could not send echo.")
Return, NumGet(Reply,8,"UInt")
}
RoundTripTimeList(AddressList,Timeout = 800)
{
Count := AddressList.MaxIndex()
If Count > 64 ;MAXIMUM_WAIT_OBJECTS
throw Exception("Could not send over 64 requests.")
If DllCall("LoadLibrary","Str","ws2_32","UPtr") = 0 ;NULL
throw Exception("Could not load WinSock library.")
If DllCall("LoadLibrary","Str","icmp","UPtr") = 0 ;NULL
throw Exception("Could not load ICMP library.")
hPort := DllCall("icmp\IcmpCreateFile","UPtr") ;open port
If hPort = -1 ;INVALID_HANDLE_VALUE
throw Exception("Could not open port.")
Replies := []
Result := []
StructLength := 250 + 20 + (A_PtrSize * 2) ;ICMP_ECHO_REPLY structure
VarSetCapacity(Events,Count * A_PtrSize)
For Index, Address In AddressList
{
NumericAddress := DllCall("ws2_32\inet_addr","AStr",Address,"UInt")
If NumericAddress = 0xFFFFFFFF ;INADDR_NONE
throw Exception("Could not convert IP address string to numeric format.")
hEvent := DllCall("CreateEvent"
,"UPtr",0 ;security attributes structure
,"UInt",True ;manual reset event
,"UInt",False ;initially not signalled
,"UPtr",0 ;event name
,"UPtr")
If !hEvent
throw Exception("Could not create event.")
NumPut(hEvent,Events,(Index - 1) * A_PtrSize)
Replies.SetCapacity(Index,StructLength)
DllCall("icmp\IcmpSendEcho2"
,"UPtr",hPort ;ICMP handle
,"UPtr",hEvent ;event handle
,"UPtr",0 ;APC routine handle
,"UPtr",0 ;APC routine context
,"UInt",NumericAddress ;IP address
,"Str","" ;request data
,"UShort",0 ;length of request data
,"UPtr",0 ;pointer to IP options structure
,"UPtr",Replies.GetAddress(Index) ;reply buffer
,"UInt",StructLength ;length of reply buffer
,"UInt",Timeout) ;ping timeout
If A_LastError != 0x3E5 ;ERROR_IO_PENDING
throw Exception("Could not send echo.")
}
While, Replies.MaxIndex()
{
Index := DllCall("WaitForMultipleObjects","UInt",Count,"UPtr",&Events,"UInt",False,"UInt",Timeout * 2)
If (Index < 0 || Index >= Count) ;WAIT_OBJECT_0, WAIT_OBJECT_0 + Count - 1
throw Exception("Could not detect ping completions." . Index . " " . A_LastError)
If !DllCall("ResetEvent","UPtr",NumGet(Events,Index * A_PtrSize)) ;reset event to nonsignalled state
throw Exception("Could not reset ping event.")
Index ++ ;zero based index to one based
Status := NumGet(Replies.GetAddress(Index),4,"UInt")
If Status In 11002,11003,11004,11005,11010 ;IP_DEST_NET_UNREACHABLE, IP_DEST_HOST_UNREACHABLE, IP_DEST_PROT_UNREACHABLE, IP_DEST_PORT_UNREACHABLE, IP_REQ_TIMED_OUT
Result[Index] := -1
Else If Status = 0 ;IP_SUCCESS
Result[Index] := NumGet(Replies.GetAddress(Index),8,"UInt") ;obtain round trip time
Else
throw Exception("Could not retrieve echo response." . Status)
Replies.Remove(Index,"") ;remove reply entry to signify ping completion
}
Loop, %Count%
{
If !DllCall("CloseHandle","UPtr",NumGet(Events,(A_Index - 1) * A_PtrSize)) ;close event
throw Exception("Could not close event.")
}
If !DllCall("icmp\IcmpCloseHandle","UInt",hPort) ;close port
throw Exception("Could not close port.")
Return, Result
}