2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS ping utility
4 * FILE: applications/cmdutils/arping/arping.c
5 * PURPOSE: Network test utility
6 * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
9 #define WIN32_NO_STATUS
27 WCHAR TargetName
[256];
28 WCHAR SourceName
[256];
36 LARGE_INTEGER TicksPerMs
;
37 LARGE_INTEGER TicksPerUs
;
38 BOOL UsePerformanceCounter
;
42 void FormatOutput(UINT uID
, ...)
49 PCHAR pAnsiBuf
= AnsiBuf
;
55 if (!LoadString(GetModuleHandle(NULL
), uID
,
56 Format
, sizeof(Format
) / sizeof(WCHAR
)))
61 va_start(valist
, uID
);
63 DataLength
= FormatMessage(FORMAT_MESSAGE_FROM_STRING
, Format
, 0, 0, Buf
,\
64 sizeof(Buf
) / sizeof(WCHAR
), &valist
);
68 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER
)
74 DataLength
= FormatMessage(FORMAT_MESSAGE_FROM_STRING
|\
75 FORMAT_MESSAGE_ALLOCATE_BUFFER
,\
76 Format
, 0, 0, (LPWSTR
)&pBuf
, 0, &valist
);
85 if(GetFileType(hStdOutput
) == FILE_TYPE_CHAR
)
87 /* Is a console or a printer */
88 WriteConsole(hStdOutput
, pBuf
, DataLength
, &written
, NULL
);
92 /* Is a pipe, socket, file or other */
93 AnsiLength
= WideCharToMultiByte(CP_ACP
, 0, pBuf
, DataLength
,\
96 if(AnsiLength
>= sizeof(AnsiBuf
))
97 pAnsiBuf
= (PCHAR
)HeapAlloc(GetProcessHeap(), 0, AnsiLength
);
99 AnsiLength
= WideCharToMultiByte(CP_OEMCP
, 0, pBuf
, DataLength
,\
100 pAnsiBuf
, AnsiLength
, " ", NULL
);
102 WriteFile(hStdOutput
, pAnsiBuf
, AnsiLength
, &written
, NULL
);
104 if(pAnsiBuf
!= AnsiBuf
)
105 HeapFree(NULL
, 0, pAnsiBuf
);
112 static VOID
Usage(VOID
)
114 FormatOutput(IDS_USAGE
);
117 static BOOL
ParseCmdline(int argc
, LPWSTR argv
[])
127 for (i
= 1; i
< argc
; i
++)
129 if (argv
[i
][0] == L
'-' || argv
[i
][0] == L
'/')
133 case L
't': NeverStop
= TRUE
; break;
137 PingCount
= wcstoul(argv
[++i
], NULL
, 0);
141 FormatOutput(IDS_BAD_VALUE_OPTION_N
, UINT_MAX
);
147 FormatOutput(IDS_BAD_OPTION_FORMAT
, argv
[i
]);
153 if (SourceName
[0] != 0)
155 FormatOutput(IDS_BAD_PARAMETER
, argv
[i
]);
161 wcscpy(SourceName
, argv
[++i
]);
165 FormatOutput(IDS_BAD_OPTION_FORMAT
, argv
[i
]);
175 FormatOutput(IDS_BAD_OPTION
, argv
[i
]);
181 if (TargetName
[0] != 0)
183 FormatOutput(IDS_BAD_PARAMETER
, argv
[i
]);
188 wcscpy(TargetName
, argv
[i
]);
193 if (TargetName
[0] == 0)
195 FormatOutput(IDS_DEST_MUST_BE_SPECIFIED
);
199 if (SourceName
[0] == 0)
201 FormatOutput(IDS_SRC_MUST_BE_SPECIFIED
);
208 static BOOL WINAPI
StopLoop(DWORD dwCtrlType
)
216 static BOOL
Setup(VOID
)
218 WORD wVersionRequested
;
222 CHAR aTargetName
[256];
225 wVersionRequested
= MAKEWORD(2, 2);
227 Status
= WSAStartup(wVersionRequested
, &WsaData
);
230 FormatOutput(IDS_COULD_NOT_INIT_WINSOCK
);
234 if (!WideCharToMultiByte(CP_ACP
, 0, TargetName
, -1, aTargetName
,
235 sizeof(aTargetName
), NULL
, NULL
))
237 FormatOutput(IDS_UNKNOWN_HOST
, TargetName
);
242 TargetAddr
= inet_addr(aTargetName
);
243 if (TargetAddr
== INADDR_NONE
)
245 phe
= gethostbyname(aTargetName
);
248 FormatOutput(IDS_UNKNOWN_HOST
, TargetName
);
252 CopyMemory(&TargetAddr
, phe
->h_addr
, phe
->h_length
);
255 Target
.S_un
.S_addr
= TargetAddr
;
256 swprintf(TargetIP
, L
"%d.%d.%d.%d", Target
.S_un
.S_un_b
.s_b1
,
257 Target
.S_un
.S_un_b
.s_b2
,
258 Target
.S_un
.S_un_b
.s_b3
,
259 Target
.S_un
.S_un_b
.s_b4
);
261 if (!WideCharToMultiByte(CP_ACP
, 0, SourceName
, -1, aTargetName
,
262 sizeof(aTargetName
), NULL
, NULL
))
264 FormatOutput(IDS_UNKNOWN_HOST
, SourceName
);
268 SourceAddr
= inet_addr(aTargetName
);
269 if (SourceAddr
== INADDR_NONE
)
271 FormatOutput(IDS_UNKNOWN_HOST
, SourceName
);
275 SetConsoleCtrlHandler(StopLoop
, TRUE
);
280 static VOID
Cleanup(VOID
)
285 static VOID
QueryTime(PLARGE_INTEGER Time
)
287 if (UsePerformanceCounter
)
289 if (QueryPerformanceCounter(Time
) == 0)
291 /* This should not happen, but we fall
292 back to GetCurrentTick() if it does */
293 Time
->u
.LowPart
= (ULONG
)GetTickCount();
294 Time
->u
.HighPart
= 0;
296 /* 1 tick per millisecond for GetCurrentTick() */
297 TicksPerMs
.QuadPart
= 1;
298 /* GetCurrentTick() cannot handle microseconds */
299 TicksPerUs
.QuadPart
= 1;
301 UsePerformanceCounter
= FALSE
;
306 Time
->u
.LowPart
= (ULONG
)GetTickCount();
307 Time
->u
.HighPart
= 0;
311 static VOID
TimeToMsString(LPWSTR String
, ULONG Length
, LARGE_INTEGER Time
)
314 LARGE_INTEGER LargeTime
;
317 LargeTime
.QuadPart
= Time
.QuadPart
/ TicksPerMs
.QuadPart
;
319 _i64tow(LargeTime
.QuadPart
, Convstr
, 10);
320 wcscpy(String
, Convstr
);
321 ms
= String
+ wcslen(String
);
322 LoadString(GetModuleHandle(NULL
), IDS_MS
, ms
, Length
- (ms
- String
));
325 static BOOL
Ping(VOID
)
327 LARGE_INTEGER RelativeTime
;
328 LARGE_INTEGER LargeTime
;
329 LARGE_INTEGER SentTime
;
337 QueryTime(&SentTime
);
338 Size
= sizeof(TargetHW
);
339 memset(TargetHW
, 0xff, Size
);
341 Ret
= SendARP(TargetAddr
, SourceAddr
, (PULONG
)TargetHW
, &Size
);
342 if (Ret
== ERROR_SUCCESS
)
344 QueryTime(&LargeTime
);
346 RelativeTime
.QuadPart
= (LargeTime
.QuadPart
- SentTime
.QuadPart
);
348 if ((RelativeTime
.QuadPart
/ TicksPerMs
.QuadPart
) < 1)
351 LoadString(GetModuleHandle(NULL
), IDS_1MS
, Time
, sizeof(Time
) / sizeof(WCHAR
));
356 TimeToMsString(Time
, sizeof(Time
) / sizeof(WCHAR
), RelativeTime
);
359 swprintf(StrHwAddr
, L
"%02x:%02x:%02x:%02x:%02x:%02x", TargetHW
[0], TargetHW
[1],
360 TargetHW
[2], TargetHW
[3],
361 TargetHW
[4], TargetHW
[5]);
362 FormatOutput(IDS_REPLY_FROM
, TargetIP
, StrHwAddr
, Sign
, Time
);
371 int wmain(int argc
, LPWSTR argv
[])
374 LARGE_INTEGER PerformanceCounterFrequency
;
378 hStdOutput
= GetStdHandle(STD_OUTPUT_HANDLE
);
380 UsePerformanceCounter
= QueryPerformanceFrequency(&PerformanceCounterFrequency
);
382 if (UsePerformanceCounter
)
384 /* Performance counters may return incorrect results on some multiprocessor
385 platforms so we restrict execution on the first processor. This may fail
386 on Windows NT so we fall back to GetCurrentTick() for timing */
387 if (SetThreadAffinityMask (GetCurrentThread(), 1) == 0)
388 UsePerformanceCounter
= FALSE
;
390 /* Convert frequency to ticks per millisecond */
391 TicksPerMs
.QuadPart
= PerformanceCounterFrequency
.QuadPart
/ 1000;
392 /* And to ticks per microsecond */
393 TicksPerUs
.QuadPart
= PerformanceCounterFrequency
.QuadPart
/ 1000000;
395 if (!UsePerformanceCounter
)
397 /* 1 tick per millisecond for GetCurrentTick() */
398 TicksPerMs
.QuadPart
= 1;
399 /* GetCurrentTick() cannot handle microseconds */
400 TicksPerUs
.QuadPart
= 1;
403 if (!ParseCmdline(argc
, argv
) || !Setup())
408 FormatOutput(IDS_ARPING_TO_FROM
, TargetIP
, SourceName
);
411 while (Count
< PingCount
|| NeverStop
)
415 if (Count
< PingCount
|| NeverStop
)
421 FormatOutput(IDS_ARPING_STATISTICS
, Sent
, Received
);