1c2c66affSColin Finck /*
2c2c66affSColin Finck * COPYRIGHT: See COPYING in the top level directory
3c2c66affSColin Finck * PROJECT: ReactOS ping utility
4c2c66affSColin Finck * FILE: applications/cmdutils/arping/arping.c
5c2c66affSColin Finck * PURPOSE: Network test utility
6c2c66affSColin Finck * PROGRAMMERS: Pierre Schweitzer <pierre@reactos.org>
7c2c66affSColin Finck */
8c2c66affSColin Finck
9c2c66affSColin Finck #define WIN32_NO_STATUS
10c2c66affSColin Finck #include <stdarg.h>
11c2c66affSColin Finck #include <windef.h>
12c2c66affSColin Finck #include <winbase.h>
13c2c66affSColin Finck #include <winuser.h>
14c2c66affSColin Finck #include <winnls.h>
15c2c66affSColin Finck #include <wincon.h>
16c2c66affSColin Finck #define _INC_WINDOWS
17c2c66affSColin Finck #include <ws2tcpip.h>
18c2c66affSColin Finck #include <iphlpapi.h>
19c2c66affSColin Finck #include <ws2def.h>
20c2c66affSColin Finck #include <stdio.h>
21c2c66affSColin Finck #include <stdlib.h>
22c2c66affSColin Finck
23c2c66affSColin Finck #include "resource.h"
24c2c66affSColin Finck
25c2c66affSColin Finck BOOL NeverStop;
26c2c66affSColin Finck UINT PingCount;
27c2c66affSColin Finck WCHAR TargetName[256];
28c2c66affSColin Finck WCHAR SourceName[256];
29c2c66affSColin Finck DWORD SourceAddr;
30c2c66affSColin Finck DWORD TargetAddr;
31c2c66affSColin Finck WCHAR TargetIP[16];
32c2c66affSColin Finck WCHAR SourceIP[16];
33c2c66affSColin Finck SOCKADDR_IN Target;
34c2c66affSColin Finck HANDLE hStdOutput;
35c2c66affSColin Finck ULONG Timeout;
36c2c66affSColin Finck LARGE_INTEGER TicksPerMs;
37c2c66affSColin Finck LARGE_INTEGER TicksPerUs;
38c2c66affSColin Finck BOOL UsePerformanceCounter;
39c2c66affSColin Finck UINT Sent;
40c2c66affSColin Finck UINT Received;
41c2c66affSColin Finck
FormatOutput(UINT uID,...)42c2c66affSColin Finck void FormatOutput(UINT uID, ...)
43c2c66affSColin Finck {
44c2c66affSColin Finck va_list valist;
45c2c66affSColin Finck
46c2c66affSColin Finck WCHAR Buf[1024];
47c2c66affSColin Finck CHAR AnsiBuf[1024];
48c2c66affSColin Finck LPWSTR pBuf = Buf;
49c2c66affSColin Finck PCHAR pAnsiBuf = AnsiBuf;
50c2c66affSColin Finck WCHAR Format[1024];
51c2c66affSColin Finck DWORD written;
52c2c66affSColin Finck UINT DataLength;
53c2c66affSColin Finck int AnsiLength;
54c2c66affSColin Finck
55c2c66affSColin Finck if (!LoadString(GetModuleHandle(NULL), uID,
56c2c66affSColin Finck Format, sizeof(Format) / sizeof(WCHAR)))
57c2c66affSColin Finck {
58c2c66affSColin Finck return;
59c2c66affSColin Finck }
60c2c66affSColin Finck
61c2c66affSColin Finck va_start(valist, uID);
62c2c66affSColin Finck DataLength = FormatMessage(FORMAT_MESSAGE_FROM_STRING, Format, 0, 0, Buf,\
63c2c66affSColin Finck sizeof(Buf) / sizeof(WCHAR), &valist);
64*cd4db318SSerge Gautherie va_end(valist);
65c2c66affSColin Finck
66c2c66affSColin Finck if(!DataLength)
67c2c66affSColin Finck {
68c2c66affSColin Finck if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
69c2c66affSColin Finck {
70c2c66affSColin Finck return;
71c2c66affSColin Finck }
72c2c66affSColin Finck
73*cd4db318SSerge Gautherie va_start(valist, uID);
74c2c66affSColin Finck DataLength = FormatMessage(FORMAT_MESSAGE_FROM_STRING |\
75c2c66affSColin Finck FORMAT_MESSAGE_ALLOCATE_BUFFER,\
76c2c66affSColin Finck Format, 0, 0, (LPWSTR)&pBuf, 0, &valist);
77*cd4db318SSerge Gautherie va_end(valist);
78c2c66affSColin Finck }
79c2c66affSColin Finck
80c2c66affSColin Finck if(!DataLength)
81c2c66affSColin Finck {
82c2c66affSColin Finck return;
83c2c66affSColin Finck }
84c2c66affSColin Finck
85c2c66affSColin Finck if(GetFileType(hStdOutput) == FILE_TYPE_CHAR)
86c2c66affSColin Finck {
87c2c66affSColin Finck /* Is a console or a printer */
88c2c66affSColin Finck WriteConsole(hStdOutput, pBuf, DataLength, &written, NULL);
89c2c66affSColin Finck }
90c2c66affSColin Finck else
91c2c66affSColin Finck {
92c2c66affSColin Finck /* Is a pipe, socket, file or other */
93c2c66affSColin Finck AnsiLength = WideCharToMultiByte(CP_ACP, 0, pBuf, DataLength,\
94c2c66affSColin Finck NULL, 0, NULL, NULL);
95c2c66affSColin Finck
96c2c66affSColin Finck if(AnsiLength >= sizeof(AnsiBuf))
97c2c66affSColin Finck pAnsiBuf = (PCHAR)HeapAlloc(GetProcessHeap(), 0, AnsiLength);
98c2c66affSColin Finck
99c2c66affSColin Finck AnsiLength = WideCharToMultiByte(CP_OEMCP, 0, pBuf, DataLength,\
100c2c66affSColin Finck pAnsiBuf, AnsiLength, " ", NULL);
101c2c66affSColin Finck
102c2c66affSColin Finck WriteFile(hStdOutput, pAnsiBuf, AnsiLength, &written, NULL);
103c2c66affSColin Finck
104c2c66affSColin Finck if(pAnsiBuf != AnsiBuf)
105c2c66affSColin Finck HeapFree(NULL, 0, pAnsiBuf);
106c2c66affSColin Finck }
107c2c66affSColin Finck
108c2c66affSColin Finck if(pBuf != Buf)
109c2c66affSColin Finck LocalFree(pBuf);
110c2c66affSColin Finck }
111c2c66affSColin Finck
Usage(VOID)112c2c66affSColin Finck static VOID Usage(VOID)
113c2c66affSColin Finck {
114c2c66affSColin Finck FormatOutput(IDS_USAGE);
115c2c66affSColin Finck }
116c2c66affSColin Finck
ParseCmdline(int argc,LPWSTR argv[])117c2c66affSColin Finck static BOOL ParseCmdline(int argc, LPWSTR argv[])
118c2c66affSColin Finck {
119c2c66affSColin Finck INT i;
120c2c66affSColin Finck
121c2c66affSColin Finck if (argc < 3)
122c2c66affSColin Finck {
123c2c66affSColin Finck Usage();
124c2c66affSColin Finck return FALSE;
125c2c66affSColin Finck }
126c2c66affSColin Finck
127c2c66affSColin Finck for (i = 1; i < argc; i++)
128c2c66affSColin Finck {
129c2c66affSColin Finck if (argv[i][0] == L'-' || argv[i][0] == L'/')
130c2c66affSColin Finck {
131c2c66affSColin Finck switch (argv[i][1])
132c2c66affSColin Finck {
133c2c66affSColin Finck case L't': NeverStop = TRUE; break;
134c2c66affSColin Finck case L'n':
135c2c66affSColin Finck if (i + 1 < argc)
136c2c66affSColin Finck {
137c2c66affSColin Finck PingCount = wcstoul(argv[++i], NULL, 0);
138c2c66affSColin Finck
139c2c66affSColin Finck if (PingCount == 0)
140c2c66affSColin Finck {
141c2c66affSColin Finck FormatOutput(IDS_BAD_VALUE_OPTION_N, UINT_MAX);
142c2c66affSColin Finck return FALSE;
143c2c66affSColin Finck }
144c2c66affSColin Finck }
145c2c66affSColin Finck else
146c2c66affSColin Finck {
147c2c66affSColin Finck FormatOutput(IDS_BAD_OPTION_FORMAT, argv[i]);
148c2c66affSColin Finck return FALSE;
149c2c66affSColin Finck }
150c2c66affSColin Finck break;
151c2c66affSColin Finck
152c2c66affSColin Finck case L's':
153c2c66affSColin Finck if (SourceName[0] != 0)
154c2c66affSColin Finck {
155c2c66affSColin Finck FormatOutput(IDS_BAD_PARAMETER, argv[i]);
156c2c66affSColin Finck return FALSE;
157c2c66affSColin Finck }
158c2c66affSColin Finck
159c2c66affSColin Finck if (i + 1 < argc)
160c2c66affSColin Finck {
161c2c66affSColin Finck wcscpy(SourceName, argv[++i]);
162c2c66affSColin Finck }
163c2c66affSColin Finck else
164c2c66affSColin Finck {
165c2c66affSColin Finck FormatOutput(IDS_BAD_OPTION_FORMAT, argv[i]);
166c2c66affSColin Finck return FALSE;
167c2c66affSColin Finck }
168c2c66affSColin Finck break;
169c2c66affSColin Finck
170c2c66affSColin Finck case '?':
171c2c66affSColin Finck Usage();
172c2c66affSColin Finck return FALSE;
173c2c66affSColin Finck
174c2c66affSColin Finck default:
175c2c66affSColin Finck FormatOutput(IDS_BAD_OPTION, argv[i]);
176c2c66affSColin Finck return FALSE;
177c2c66affSColin Finck }
178c2c66affSColin Finck }
179c2c66affSColin Finck else
180c2c66affSColin Finck {
181c2c66affSColin Finck if (TargetName[0] != 0)
182c2c66affSColin Finck {
183c2c66affSColin Finck FormatOutput(IDS_BAD_PARAMETER, argv[i]);
184c2c66affSColin Finck return FALSE;
185c2c66affSColin Finck }
186c2c66affSColin Finck else
187c2c66affSColin Finck {
188c2c66affSColin Finck wcscpy(TargetName, argv[i]);
189c2c66affSColin Finck }
190c2c66affSColin Finck }
191c2c66affSColin Finck }
192c2c66affSColin Finck
193c2c66affSColin Finck if (TargetName[0] == 0)
194c2c66affSColin Finck {
195c2c66affSColin Finck FormatOutput(IDS_DEST_MUST_BE_SPECIFIED);
196c2c66affSColin Finck return FALSE;
197c2c66affSColin Finck }
198c2c66affSColin Finck
199c2c66affSColin Finck if (SourceName[0] == 0)
200c2c66affSColin Finck {
201c2c66affSColin Finck FormatOutput(IDS_SRC_MUST_BE_SPECIFIED);
202c2c66affSColin Finck return FALSE;
203c2c66affSColin Finck }
204c2c66affSColin Finck
205c2c66affSColin Finck return TRUE;
206c2c66affSColin Finck }
207c2c66affSColin Finck
StopLoop(DWORD dwCtrlType)208c2c66affSColin Finck static BOOL WINAPI StopLoop(DWORD dwCtrlType)
209c2c66affSColin Finck {
210c2c66affSColin Finck NeverStop = FALSE;
211c2c66affSColin Finck PingCount = 0;
212c2c66affSColin Finck
213c2c66affSColin Finck return TRUE;
214c2c66affSColin Finck }
215c2c66affSColin Finck
Setup(VOID)216c2c66affSColin Finck static BOOL Setup(VOID)
217c2c66affSColin Finck {
218c2c66affSColin Finck WORD wVersionRequested;
219c2c66affSColin Finck WSADATA WsaData;
220c2c66affSColin Finck INT Status;
221c2c66affSColin Finck PHOSTENT phe;
222c2c66affSColin Finck CHAR aTargetName[256];
223c2c66affSColin Finck IN_ADDR Target;
224c2c66affSColin Finck
225c2c66affSColin Finck wVersionRequested = MAKEWORD(2, 2);
226c2c66affSColin Finck
227c2c66affSColin Finck Status = WSAStartup(wVersionRequested, &WsaData);
228c2c66affSColin Finck if (Status != 0)
229c2c66affSColin Finck {
230c2c66affSColin Finck FormatOutput(IDS_COULD_NOT_INIT_WINSOCK);
231c2c66affSColin Finck return FALSE;
232c2c66affSColin Finck }
233c2c66affSColin Finck
234c2c66affSColin Finck if (!WideCharToMultiByte(CP_ACP, 0, TargetName, -1, aTargetName,
235c2c66affSColin Finck sizeof(aTargetName), NULL, NULL))
236c2c66affSColin Finck {
237c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, TargetName);
238c2c66affSColin Finck return FALSE;
239c2c66affSColin Finck }
240c2c66affSColin Finck
241c2c66affSColin Finck phe = NULL;
242c2c66affSColin Finck TargetAddr = inet_addr(aTargetName);
243c2c66affSColin Finck if (TargetAddr == INADDR_NONE)
244c2c66affSColin Finck {
245c2c66affSColin Finck phe = gethostbyname(aTargetName);
246c2c66affSColin Finck if (phe == NULL)
247c2c66affSColin Finck {
248c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, TargetName);
249c2c66affSColin Finck return FALSE;
250c2c66affSColin Finck }
251c2c66affSColin Finck
252c2c66affSColin Finck CopyMemory(&TargetAddr, phe->h_addr, phe->h_length);
253c2c66affSColin Finck }
254c2c66affSColin Finck
255c2c66affSColin Finck Target.S_un.S_addr = TargetAddr;
256c2c66affSColin Finck swprintf(TargetIP, L"%d.%d.%d.%d", Target.S_un.S_un_b.s_b1,
257c2c66affSColin Finck Target.S_un.S_un_b.s_b2,
258c2c66affSColin Finck Target.S_un.S_un_b.s_b3,
259c2c66affSColin Finck Target.S_un.S_un_b.s_b4);
260c2c66affSColin Finck
261c2c66affSColin Finck if (!WideCharToMultiByte(CP_ACP, 0, SourceName, -1, aTargetName,
262c2c66affSColin Finck sizeof(aTargetName), NULL, NULL))
263c2c66affSColin Finck {
264c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, SourceName);
265c2c66affSColin Finck return FALSE;
266c2c66affSColin Finck }
267c2c66affSColin Finck
268c2c66affSColin Finck SourceAddr = inet_addr(aTargetName);
269c2c66affSColin Finck if (SourceAddr == INADDR_NONE)
270c2c66affSColin Finck {
271c2c66affSColin Finck FormatOutput(IDS_UNKNOWN_HOST, SourceName);
272c2c66affSColin Finck return FALSE;
273c2c66affSColin Finck }
274c2c66affSColin Finck
275c2c66affSColin Finck SetConsoleCtrlHandler(StopLoop, TRUE);
276c2c66affSColin Finck
277c2c66affSColin Finck return TRUE;
278c2c66affSColin Finck }
279c2c66affSColin Finck
Cleanup(VOID)280c2c66affSColin Finck static VOID Cleanup(VOID)
281c2c66affSColin Finck {
282c2c66affSColin Finck WSACleanup();
283c2c66affSColin Finck }
284c2c66affSColin Finck
QueryTime(PLARGE_INTEGER Time)285c2c66affSColin Finck static VOID QueryTime(PLARGE_INTEGER Time)
286c2c66affSColin Finck {
287c2c66affSColin Finck if (UsePerformanceCounter)
288c2c66affSColin Finck {
289c2c66affSColin Finck if (QueryPerformanceCounter(Time) == 0)
290c2c66affSColin Finck {
291c2c66affSColin Finck /* This should not happen, but we fall
292c2c66affSColin Finck back to GetCurrentTick() if it does */
293c2c66affSColin Finck Time->u.LowPart = (ULONG)GetTickCount();
294c2c66affSColin Finck Time->u.HighPart = 0;
295c2c66affSColin Finck
296c2c66affSColin Finck /* 1 tick per millisecond for GetCurrentTick() */
297c2c66affSColin Finck TicksPerMs.QuadPart = 1;
298c2c66affSColin Finck /* GetCurrentTick() cannot handle microseconds */
299c2c66affSColin Finck TicksPerUs.QuadPart = 1;
300c2c66affSColin Finck
301c2c66affSColin Finck UsePerformanceCounter = FALSE;
302c2c66affSColin Finck }
303c2c66affSColin Finck }
304c2c66affSColin Finck else
305c2c66affSColin Finck {
306c2c66affSColin Finck Time->u.LowPart = (ULONG)GetTickCount();
307c2c66affSColin Finck Time->u.HighPart = 0;
308c2c66affSColin Finck }
309c2c66affSColin Finck }
310c2c66affSColin Finck
TimeToMsString(LPWSTR String,ULONG Length,LARGE_INTEGER Time)311c2c66affSColin Finck static VOID TimeToMsString(LPWSTR String, ULONG Length, LARGE_INTEGER Time)
312c2c66affSColin Finck {
313c2c66affSColin Finck WCHAR Convstr[40];
314c2c66affSColin Finck LARGE_INTEGER LargeTime;
315c2c66affSColin Finck LPWSTR ms;
316c2c66affSColin Finck
317c2c66affSColin Finck LargeTime.QuadPart = Time.QuadPart / TicksPerMs.QuadPart;
318c2c66affSColin Finck
319c2c66affSColin Finck _i64tow(LargeTime.QuadPart, Convstr, 10);
320c2c66affSColin Finck wcscpy(String, Convstr);
321c2c66affSColin Finck ms = String + wcslen(String);
322c2c66affSColin Finck LoadString(GetModuleHandle(NULL), IDS_MS, ms, Length - (ms - String));
323c2c66affSColin Finck }
324c2c66affSColin Finck
Ping(VOID)325c2c66affSColin Finck static BOOL Ping(VOID)
326c2c66affSColin Finck {
327c2c66affSColin Finck LARGE_INTEGER RelativeTime;
328c2c66affSColin Finck LARGE_INTEGER LargeTime;
329c2c66affSColin Finck LARGE_INTEGER SentTime;
330c2c66affSColin Finck DWORD Ret;
331c2c66affSColin Finck BYTE TargetHW[6];
332c2c66affSColin Finck ULONG Size;
333c2c66affSColin Finck WCHAR Sign[2];
334c2c66affSColin Finck WCHAR Time[100];
335c2c66affSColin Finck WCHAR StrHwAddr[18];
336c2c66affSColin Finck
337c2c66affSColin Finck QueryTime(&SentTime);
338c2c66affSColin Finck Size = sizeof(TargetHW);
339c2c66affSColin Finck memset(TargetHW, 0xff, Size);
340c2c66affSColin Finck ++Sent;
341c2c66affSColin Finck Ret = SendARP(TargetAddr, SourceAddr, (PULONG)TargetHW, &Size);
342c2c66affSColin Finck if (Ret == ERROR_SUCCESS)
343c2c66affSColin Finck {
344c2c66affSColin Finck QueryTime(&LargeTime);
345c2c66affSColin Finck
346c2c66affSColin Finck RelativeTime.QuadPart = (LargeTime.QuadPart - SentTime.QuadPart);
347c2c66affSColin Finck
348c2c66affSColin Finck if ((RelativeTime.QuadPart / TicksPerMs.QuadPart) < 1)
349c2c66affSColin Finck {
350c2c66affSColin Finck wcscpy(Sign, L"<");
351c2c66affSColin Finck LoadString(GetModuleHandle(NULL), IDS_1MS, Time, sizeof(Time) / sizeof(WCHAR));
352c2c66affSColin Finck }
353c2c66affSColin Finck else
354c2c66affSColin Finck {
355c2c66affSColin Finck wcscpy(Sign, L"=");
356c2c66affSColin Finck TimeToMsString(Time, sizeof(Time) / sizeof(WCHAR), RelativeTime);
357c2c66affSColin Finck }
358c2c66affSColin Finck
359c2c66affSColin Finck swprintf(StrHwAddr, L"%02x:%02x:%02x:%02x:%02x:%02x", TargetHW[0], TargetHW[1],
360c2c66affSColin Finck TargetHW[2], TargetHW[3],
361c2c66affSColin Finck TargetHW[4], TargetHW[5]);
362c2c66affSColin Finck FormatOutput(IDS_REPLY_FROM, TargetIP, StrHwAddr, Sign, Time);
363c2c66affSColin Finck Received++;
364c2c66affSColin Finck
365c2c66affSColin Finck return TRUE;
366c2c66affSColin Finck }
367c2c66affSColin Finck
368c2c66affSColin Finck return FALSE;
369c2c66affSColin Finck }
370c2c66affSColin Finck
wmain(int argc,LPWSTR argv[])371c2c66affSColin Finck int wmain(int argc, LPWSTR argv[])
372c2c66affSColin Finck {
373c2c66affSColin Finck UINT Count;
374c2c66affSColin Finck LARGE_INTEGER PerformanceCounterFrequency;
375c2c66affSColin Finck
376c2c66affSColin Finck PingCount = 4;
377c2c66affSColin Finck Timeout = 1000;
378c2c66affSColin Finck hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
379c2c66affSColin Finck
380c2c66affSColin Finck UsePerformanceCounter = QueryPerformanceFrequency(&PerformanceCounterFrequency);
381c2c66affSColin Finck
382c2c66affSColin Finck if (UsePerformanceCounter)
383c2c66affSColin Finck {
384c2c66affSColin Finck /* Performance counters may return incorrect results on some multiprocessor
385c2c66affSColin Finck platforms so we restrict execution on the first processor. This may fail
386c2c66affSColin Finck on Windows NT so we fall back to GetCurrentTick() for timing */
387c2c66affSColin Finck if (SetThreadAffinityMask (GetCurrentThread(), 1) == 0)
388c2c66affSColin Finck UsePerformanceCounter = FALSE;
389c2c66affSColin Finck
390c2c66affSColin Finck /* Convert frequency to ticks per millisecond */
391c2c66affSColin Finck TicksPerMs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000;
392c2c66affSColin Finck /* And to ticks per microsecond */
393c2c66affSColin Finck TicksPerUs.QuadPart = PerformanceCounterFrequency.QuadPart / 1000000;
394c2c66affSColin Finck }
395c2c66affSColin Finck if (!UsePerformanceCounter)
396c2c66affSColin Finck {
397c2c66affSColin Finck /* 1 tick per millisecond for GetCurrentTick() */
398c2c66affSColin Finck TicksPerMs.QuadPart = 1;
399c2c66affSColin Finck /* GetCurrentTick() cannot handle microseconds */
400c2c66affSColin Finck TicksPerUs.QuadPart = 1;
401c2c66affSColin Finck }
402c2c66affSColin Finck
403c2c66affSColin Finck if (!ParseCmdline(argc, argv) || !Setup())
404c2c66affSColin Finck {
405c2c66affSColin Finck return 1;
406c2c66affSColin Finck }
407c2c66affSColin Finck
408c2c66affSColin Finck FormatOutput(IDS_ARPING_TO_FROM, TargetIP, SourceName);
409c2c66affSColin Finck
410c2c66affSColin Finck Count = 0;
411c2c66affSColin Finck while (Count < PingCount || NeverStop)
412c2c66affSColin Finck {
413c2c66affSColin Finck Ping();
414c2c66affSColin Finck Count++;
415c2c66affSColin Finck if (Count < PingCount || NeverStop)
416c2c66affSColin Finck Sleep(Timeout);
417c2c66affSColin Finck }
418c2c66affSColin Finck
419c2c66affSColin Finck Cleanup();
420c2c66affSColin Finck
421c2c66affSColin Finck FormatOutput(IDS_ARPING_STATISTICS, Sent, Received);
422c2c66affSColin Finck
423c2c66affSColin Finck return 0;
424c2c66affSColin Finck }
425