Use bigger buffer to avoid stack corruption, as seen when running app built with...
[reactos.git] / reactos / apps / utils / net / ping / ping.c
index 07914db..5d2efba 100644 (file)
@@ -7,23 +7,35 @@
  * 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 */
@@ -93,9 +105,29 @@ LARGE_INTEGER       TicksPerMs; /* Ticks per millisecond */
 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");
@@ -107,7 +139,7 @@ VOID Usage(VOID)
 }
 
 /* Reset configuration to default values */
-VOID Reset(VOID)
+static VOID Reset(VOID)
 {
     LARGE_INTEGER PerformanceCounterFrequency;
 
@@ -123,8 +155,8 @@ VOID Reset(VOID)
 
     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;
         }
@@ -143,13 +175,13 @@ VOID Reset(VOID)
 }
 
 /* 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;
@@ -161,7 +193,7 @@ ULONG GetULONG(LPSTR String)
 }
 
 /* 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;
 
@@ -179,12 +211,16 @@ ULONG GetULONG2(LPSTR String1, LPSTR String2, PINT i)
 }
 
 /* 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 {
@@ -210,7 +246,7 @@ BOOL ParseCmdline(int argc, char* argv[])
             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();
@@ -225,7 +261,7 @@ BOOL ParseCmdline(int argc, char* argv[])
                 printf("Bad parameter %s.\n", argv[i]);
                 return FALSE;
             } else {
-                               strcpy(TargetName, argv[i]);
+                               lstrcpy(TargetName, argv[i]);
                 FoundTarget = TRUE;
             }
         }
@@ -244,7 +280,7 @@ BOOL ParseCmdline(int argc, char* argv[])
 }
 
 /* Calculate checksum of data */
-WORD Checksum(PUSHORT data, UINT size)
+static WORD Checksum(PUSHORT data, UINT size)
 {
     ULONG sum = 0;
 
@@ -263,19 +299,19 @@ WORD Checksum(PUSHORT data, UINT size)
 }
 
 /* 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;
     }
 
@@ -293,11 +329,11 @@ BOOL Setup(VOID)
         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;
     }
@@ -307,20 +343,20 @@ BOOL Setup(VOID)
     } 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);
@@ -328,7 +364,7 @@ VOID Cleanup(VOID)
     WSACleanup();
 }
 
-VOID QueryTime(PLARGE_INTEGER Time)
+static VOID QueryTime(PLARGE_INTEGER Time)
 {
     if (UsePerformanceCounter) {
         if (QueryPerformanceCounter(Time) == 0) {
@@ -350,80 +386,90 @@ VOID QueryTime(PLARGE_INTEGER Time)
     }
 }
 
-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;
@@ -440,11 +486,11 @@ BOOL Ping(VOID)
     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);
@@ -463,10 +509,17 @@ BOOL Ping(VOID)
     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");
@@ -487,6 +540,12 @@ BOOL Ping(VOID)
     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) {
@@ -499,12 +558,14 @@ BOOL Ping(VOID)
 
     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++;
     }
 
@@ -517,9 +578,9 @@ BOOL Ping(VOID)
 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();
 
@@ -527,7 +588,7 @@ int main(int argc, char* argv[])
 
         printf("\nPinging %s [%s] with %d bytes of data:\n\n",
             TargetName, TargetIP, DataSize);
-               
+
                Count = 0;
                while ((NeverStop) || (Count < PingCount)) {
                        Ping();
@@ -552,7 +613,7 @@ int main(int argc, char* argv[])
         }
 
         if (!MinRTTSet)
-            MinRTT.QuadPart = 0;
+            MinRTT = MaxRTT;
 
         TimeToMsString(MinTime, MinRTT);
         TimeToMsString(MaxTime, MaxRTT);