* REVISIONS:
* CSH 01/09/2000 Created
*/
+
#include <winsock2.h>
#include <tchar.h>
#include <stdarg.h>
#include <string.h>
#include <stdio.h>
+
#ifndef _MSC_VER
/* FIXME: Where should this be? */
+#ifdef CopyMemory
+#undef CopyMemory
+#endif
#define CopyMemory(Destination, Source, Length) memcpy(Destination, Source, Length);
/* Should be in the header files somewhere (exported by ntdll.dll) */
long atol(const char *str);
+#ifndef __int64
+typedef long long __int64;
+#endif
+
char * _i64toa(__int64 value, char *string, int radix);
-#endif
+#endif /* _MSC_VER */
+#ifdef DBG
+#undef DBG
+#endif
/* General ICMP constants */
#define ICMP_MINSIZE 8 /* Minimum ICMP packet size */
LARGE_INTEGER TicksPerUs; /* Ticks per microsecond */
BOOL UsePerformanceCounter;
+#ifdef DBG
+/* Display the contents of a buffer */
+static VOID DisplayBuffer(
+ PVOID Buffer,
+ DWORD Size)
+{
+ UINT i;
+ PCHAR p;
+
+ printf("Buffer (0x%p) Size (0x%lX).\n", Buffer, Size);
+
+ p = (PCHAR)Buffer;
+ for (i = 0; i < Size; i++) {
+ if (i % 16 == 0) {
+ printf("\n");
+ }
+ printf("%02X ", (p[i]) & 0xFF);
+ }
+}
+#endif /* DBG */
/* Display usage information on screen */
-VOID Usage(VOID)
+static VOID Usage(VOID)
{
printf("\nUsage: ping [-t] [-n count] [-l size] [-w timeout] destination-host\n\n");
printf("Options:\n");
}
/* Reset configuration to default values */
-VOID Reset(VOID)
+static VOID Reset(VOID)
{
LARGE_INTEGER PerformanceCounterFrequency;
if (UsePerformanceCounter) {
/* Performance counters may return incorrect results on some multiprocessor
- platforms so we restrict execution on the first processor. This may fail on
- Windows NT so we fall back to GetCurrentTick() for timing */
+ platforms so we restrict execution on the first processor. This may fail
+ on Windows NT so we fall back to GetCurrentTick() for timing */
if (SetThreadAffinityMask (GetCurrentThread(), 1) == 0) {
UsePerformanceCounter = FALSE;
}
}
/* Return ULONG in a string */
-ULONG GetULONG(LPSTR String)
+static ULONG GetULONG(LPSTR String)
{
UINT i, Length;
ULONG Value;
i = 0;
- Length = strlen(String);
+ Length = (UINT)_tcslen(String);
while ((i < Length) && ((String[i] < '0') || (String[i] > '9'))) i++;
if ((i >= Length) || ((String[i] < '0') || (String[i] > '9'))) {
InvalidOption = TRUE;
}
/* Return ULONG in a string. Try next paramter if not successful */
-ULONG GetULONG2(LPSTR String1, LPSTR String2, PINT i)
+static ULONG GetULONG2(LPSTR String1, LPSTR String2, PINT i)
{
ULONG Value;
}
/* Parse command line parameters */
-BOOL ParseCmdline(int argc, char* argv[])
+static BOOL ParseCmdline(int argc, char* argv[])
{
INT i;
BOOL ShowUsage;
BOOL FoundTarget;
-
+//#if 1
+// lstrcpy(TargetName, "127.0.0.1");
+// PingCount = 1;
+// return TRUE;
+//#endif
if (argc < 2) {
ShowUsage = TRUE;
} else {
case 'f': DontFragment = TRUE; break;
case 'i': TTLValue = GetULONG2(&argv[i][2], argv[i + 1], &i); break;
case 'v': TOSValue = GetULONG2(&argv[i][2], argv[i + 1], &i); break;
- case 'w': Timeout = GetULONG2(&argv[i][2], argv[i + 1], &i); break;
+ case 'w': Timeout = GetULONG2(&argv[i][2], argv[i + 1], &i); break;
default:
printf("Bad option %s.\n", argv[i]);
Usage();
printf("Bad parameter %s.\n", argv[i]);
return FALSE;
} else {
- strcpy(TargetName, argv[i]);
+ lstrcpy(TargetName, argv[i]);
FoundTarget = TRUE;
}
}
}
/* Calculate checksum of data */
-WORD Checksum(PUSHORT data, UINT size)
+static WORD Checksum(PUSHORT data, UINT size)
{
ULONG sum = 0;
}
/* Prepare to ping target */
-BOOL Setup(VOID)
+static BOOL Setup(VOID)
{
- WORD wVersionRequested;
- WSADATA WsaData;
- INT Status;
- ULONG Addr;
- PHOSTENT phe;
+ WORD wVersionRequested;
+ WSADATA WsaData;
+ INT Status;
+ ULONG Addr;
+ PHOSTENT phe;
wVersionRequested = MAKEWORD(2, 2);
-
+
Status = WSAStartup(wVersionRequested, &WsaData);
if (Status != 0) {
- printf("Could not initialize winsock dll.\n");
+ printf("Could not initialize winsock dll.\n");
return FALSE;
}
if (phe == NULL) {
printf("Unknown host %s.\n", TargetName);
return FALSE;
- }
+ }
}
-
+
if (phe != NULL) {
- CopyMemory(&Target.sin_addr, phe->h_addr_list, phe->h_length);
+ CopyMemory(&Target.sin_addr, phe->h_addr, phe->h_length);
} else {
Target.sin_addr.s_addr = Addr;
}
} else {
Target.sin_family = AF_INET;
}
-
- TargetIP = inet_ntoa(Target.sin_addr);
- CurrentSeqNum = 0;
- SentCount = 0;
- LostCount = 0;
- MinRTT.QuadPart = 0;
- MaxRTT.QuadPart = 0;
- SumRTT.QuadPart = 0;
- MinRTTSet = FALSE;
+
+ TargetIP = inet_ntoa(Target.sin_addr);
+ CurrentSeqNum = 0;
+ SentCount = 0;
+ LostCount = 0;
+ MinRTT.QuadPart = 0;
+ MaxRTT.QuadPart = 0;
+ SumRTT.QuadPart = 0;
+ MinRTTSet = FALSE;
return TRUE;
}
/* Close socket */
-VOID Cleanup(VOID)
+static VOID Cleanup(VOID)
{
if (IcmpSock != INVALID_SOCKET)
closesocket(IcmpSock);
WSACleanup();
}
-VOID QueryTime(PLARGE_INTEGER Time)
+static VOID QueryTime(PLARGE_INTEGER Time)
{
if (UsePerformanceCounter) {
if (QueryPerformanceCounter(Time) == 0) {
}
}
-VOID TimeToMsString(LPSTR String, LARGE_INTEGER Time)
+static VOID TimeToMsString(LPSTR String, LARGE_INTEGER Time)
{
- UINT i, Length;
CHAR Convstr[40];
LARGE_INTEGER LargeTime;
LargeTime.QuadPart = Time.QuadPart / TicksPerMs.QuadPart;
- _i64toa(LargeTime.QuadPart, Convstr, 10);
- strcpy(String, Convstr);
- strcat(String, ",");
- LargeTime.QuadPart = (Time.QuadPart % TicksPerMs.QuadPart) / TicksPerUs.QuadPart;
_i64toa(LargeTime.QuadPart, Convstr, 10);
- Length = strlen(Convstr);
- if (Length < 4) {
- for (i = 0; i < 4 - Length; i++)
- strcat(String, "0");
- }
-
- strcat(String, Convstr);
+ strcpy(String, Convstr);
strcat(String, "ms");
}
/* Locate the ICMP data and print it. Returns TRUE if the packet was good,
FALSE if not */
-BOOL DecodeResponse(PCHAR buffer, UINT size, PSOCKADDR_IN from)
+static BOOL DecodeResponse(PCHAR buffer, UINT size, PSOCKADDR_IN from)
{
PIPv4_HEADER IpHeader;
PICMP_ECHO_PACKET Icmp;
- UINT IphLength;
+ UINT IphLength;
CHAR Time[100];
LARGE_INTEGER RelativeTime;
LARGE_INTEGER LargeTime;
+ CHAR Sign[2];
IpHeader = (PIPv4_HEADER)buffer;
IphLength = IpHeader->IHL * 4;
- if (size < IphLength + ICMP_MINSIZE)
+ if (size < IphLength + ICMP_MINSIZE) {
+#ifdef DBG
+ printf("Bad size (0x%X < 0x%X)\n", size, IphLength + ICMP_MINSIZE);
+#endif /* DBG */
return FALSE;
+ }
Icmp = (PICMP_ECHO_PACKET)(buffer + IphLength);
- if (Icmp->Icmp.Type != ICMPMSG_ECHOREPLY)
+ if (Icmp->Icmp.Type != ICMPMSG_ECHOREPLY) {
+#ifdef DBG
+ printf("Bad ICMP type (0x%X should be 0x%X)\n", Icmp->Icmp.Type, ICMPMSG_ECHOREPLY);
+#endif /* DBG */
return FALSE;
+ }
- if (Icmp->Icmp.Id != (USHORT)GetCurrentProcessId())
+ if (Icmp->Icmp.Id != (USHORT)GetCurrentProcessId()) {
+#ifdef DBG
+ printf("Bad ICMP id (0x%X should be 0x%X)\n", Icmp->Icmp.Id, (USHORT)GetCurrentProcessId());
+#endif /* DBG */
return FALSE;
+ }
QueryTime(&LargeTime);
RelativeTime.QuadPart = (LargeTime.QuadPart - Icmp->Timestamp.QuadPart);
- TimeToMsString(Time, RelativeTime);
+ if ((RelativeTime.QuadPart / TicksPerMs.QuadPart) < 1) {
+ strcpy(Sign, "<");
+ strcpy(Time, "1ms");
+ } else {
+ strcpy(Sign, "=");
+ TimeToMsString(Time, RelativeTime);
+ }
+
- printf("Reply from %s: bytes=%d time=%s TTL=%d\n", inet_ntoa(from->sin_addr),
- size - IphLength - sizeof(ICMP_ECHO_PACKET) , Time, IpHeader->TTL);
- if (RelativeTime.QuadPart < MinRTT.QuadPart) {
- MinRTT.QuadPart = RelativeTime.QuadPart;
+ printf("Reply from %s: bytes=%d time%s%s TTL=%d\n", inet_ntoa(from->sin_addr),
+ size - IphLength - sizeof(ICMP_ECHO_PACKET), Sign, Time, IpHeader->TTL);
+ if (RelativeTime.QuadPart < MinRTT.QuadPart || !MinRTTSet) {
+ MinRTT.QuadPart = RelativeTime.QuadPart;
MinRTTSet = TRUE;
}
if (RelativeTime.QuadPart > MaxRTT.QuadPart)
- MaxRTT.QuadPart = RelativeTime.QuadPart;
- SumRTT.QuadPart += RelativeTime.QuadPart;
+ MaxRTT.QuadPart = RelativeTime.QuadPart;
+
+ SumRTT.QuadPart += RelativeTime.QuadPart;
return TRUE;
}
/* Send and receive one ping */
-BOOL Ping(VOID)
+static BOOL Ping(VOID)
{
INT Status;
SOCKADDR From;
- UINT Length;
+ INT Length;
PVOID Buffer;
UINT Size;
PICMP_ECHO_PACKET Packet;
Packet = (PICMP_ECHO_PACKET)Buffer;
/* Assemble ICMP echo request packet */
- Packet->Icmp.Type = ICMPMSG_ECHOREQUEST;
- Packet->Icmp.Code = 0;
- Packet->Icmp.Id = (USHORT)GetCurrentProcessId();
- Packet->Icmp.SeqNum = (USHORT)CurrentSeqNum;
- Packet->Icmp.Checksum = 0;
+ Packet->Icmp.Type = ICMPMSG_ECHOREQUEST;
+ Packet->Icmp.Code = 0;
+ Packet->Icmp.Id = (USHORT)GetCurrentProcessId();
+ Packet->Icmp.SeqNum = (USHORT)CurrentSeqNum;
+ Packet->Icmp.Checksum = 0;
/* Timestamp is part of data area */
QueryTime(&Packet->Timestamp);
Timeval.tv_usec = Timeout % 1000;
Status = select(0, NULL, &Fds, NULL, &Timeval);
if ((Status != SOCKET_ERROR) && (Status != 0)) {
+
+#ifdef DBG
+ printf("Sending packet\n");
+ DisplayBuffer(Buffer, sizeof(ICMP_ECHO_PACKET) + DataSize);
+ printf("\n");
+#endif /* DBG */
+
Status = sendto(IcmpSock, Buffer, sizeof(ICMP_ECHO_PACKET) + DataSize,
0, (SOCKADDR*)&Target, sizeof(Target));
+ SentCount++;
}
- SentCount++;
if (Status == SOCKET_ERROR) {
if (WSAGetLastError() == WSAEHOSTUNREACH) {
printf("Destination host unreachable.\n");
if ((Status != SOCKET_ERROR) && (Status != 0)) {
Length = sizeof(From);
Status = recvfrom(IcmpSock, Buffer, Size, 0, &From, &Length);
+
+#ifdef DBG
+ printf("Received packet\n");
+ DisplayBuffer(Buffer, Status);
+ printf("\n");
+#endif /* DBG */
}
if (Status == SOCKET_ERROR) {
if (WSAGetLastError() != WSAETIMEDOUT) {
if (Status == 0) {
printf("Request timed out.\n");
+ LostCount++;
GlobalFree(Buffer);
return TRUE;
}
-
+
if (!DecodeResponse(Buffer, Status, (PSOCKADDR_IN)&From)) {
- printf("Request timed out.\n");
+ /* FIXME: Wait again as it could be another ICMP message type */
+ printf("Request timed out (incomplete datagram received).\n");
LostCount++;
}
int main(int argc, char* argv[])
{
UINT Count;
- CHAR MinTime[20];
- CHAR MaxTime[20];
- CHAR AvgTime[20];
+ CHAR MinTime[20];
+ CHAR MaxTime[20];
+ CHAR AvgTime[20];
Reset();
printf("\nPinging %s [%s] with %d bytes of data:\n\n",
TargetName, TargetIP, DataSize);
-
+
Count = 0;
while ((NeverStop) || (Count < PingCount)) {
Ping();
}
if (!MinRTTSet)
- MinRTT.QuadPart = 0;
+ MinRTT = MaxRTT;
TimeToMsString(MinTime, MinRTT);
TimeToMsString(MaxTime, MaxRTT);