1 /*
2  * PROJECT:     ReactOS netstat utility
3  * LICENSE:     GPL - See COPYING in the top level directory
4  * PURPOSE:     display IP stack statistics
5  * COPYRIGHT:   Copyright 2005 Ged Murphy <gedmurphy@gmail.com>
6  */
7 /*
8  * TODO:
9  * implement -b, -t, -v
10  * clean up GetIpHostName
11  */
12 
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <wchar.h>
16 
17 #define WIN32_NO_STATUS
18 #include <windef.h>
19 #include <winbase.h>
20 #define _INC_WINDOWS
21 #include <winsock2.h>
22 #include <iphlpapi.h>
23 
24 #include <conutils.h>
25 
26 #include "netstat.h"
27 #include "resource.h"
28 
29 enum ProtoType {IP, TCP, UDP, ICMP} Protocol;
30 DWORD Interval; /* time to pause between printing output */
31 
32 /* TCP endpoint states */
33 PCWSTR TcpState[] = {
34     L"???",
35     L"CLOSED",
36     L"LISTENING",
37     L"SYN_SENT",
38     L"SYN_RCVD",
39     L"ESTABLISHED",
40     L"FIN_WAIT1",
41     L"FIN_WAIT2",
42     L"CLOSE_WAIT",
43     L"CLOSING",
44     L"LAST_ACK",
45     L"TIME_WAIT",
46     L"DELETE_TCB"
47 };
48 
49 /*
50  * format message string and display output
51  */
DoFormatMessage(DWORD ErrorCode)52 VOID DoFormatMessage(DWORD ErrorCode)
53 {
54     if (ErrorCode == ERROR_SUCCESS)
55         return;
56 
57     ConMsgPuts(StdErr, FORMAT_MESSAGE_FROM_SYSTEM,
58                NULL, ErrorCode, LANG_USER_DEFAULT);
59 }
60 
DisplayTableHeader(VOID)61 VOID DisplayTableHeader(VOID)
62 {
63     ConResPuts(StdOut, IDS_ACTIVE_CONNECT);
64     ConResPuts(StdOut, IDS_DISPLAY_THEADER);
65     if (bDoShowProcessId)
66         ConResPuts(StdOut, IDS_DISPLAY_PROCESS);
67     else
68         ConPuts(StdOut, L"\n");
69 }
70 
71 /*
72  * Parse command line parameters and set any options
73  */
ParseCmdline(int argc,wchar_t * argv[])74 BOOL ParseCmdline(int argc, wchar_t* argv[])
75 {
76     LPWSTR Proto;
77     WCHAR c;
78     INT i;
79 
80     if ((argc == 1) || (iswdigit(*argv[1])))
81         bNoOptions = TRUE;
82 
83     /* Parse command line for options we have been given. */
84     for (i = 1; i < argc; i++)
85     {
86         if ((argc > 1) && (argv[i][0] == L'-' || argv[i][0] == L'/'))
87         {
88             while ((c = *++argv[i]) != L'\0')
89             {
90                 switch (towlower(c))
91                 {
92                     case L'a':
93                         bDoShowAllCons = TRUE;
94                         break;
95                     case L'b':
96                         // UNIMPLEMENTED.
97                         ConPuts(StdErr, L"'b' option is FIXME (Accepted option though unimplemented feature).\n");
98                         bDoShowProcName = TRUE;
99 #if (_WIN32_WINNT < _WIN32_WINNT_VISTA)
100                         bDoShowProcessId = TRUE;
101 #endif
102                         break;
103                     case L'e':
104                         bDoShowEthStats = TRUE;
105                         break;
106                     case L'n':
107                         bDoShowNumbers = TRUE;
108                         break;
109                     case L'o':
110                         bDoShowProcessId = TRUE;
111                         break;
112                     case L'p':
113                         bDoShowProtoCons = TRUE;
114                         if (i+1 >= argc)
115                         {
116                             DisplayTableHeader();
117                             return TRUE;
118                         }
119 
120                         Proto = argv[i+1];
121                         if (!_wcsicmp(L"IP", Proto))
122                             Protocol = IP;
123                         else if (!_wcsicmp(L"ICMP", Proto))
124                             Protocol = ICMP;
125                         else if (!_wcsicmp(L"TCP", Proto))
126                             Protocol = TCP;
127                         else if (!_wcsicmp(L"UDP", Proto))
128                             Protocol = UDP;
129                         else
130                             goto StopParsingAndShowUsageHelp;
131                         break;
132                     case L'r':
133                         bDoShowRouteTable = TRUE;
134                         break;
135                     case L's':
136                         bDoShowProtoStats = TRUE;
137                         break;
138                     case L't':
139                         // UNIMPLEMENTED.
140                         ConPuts(StdErr, L"'t' option is FIXME (Accepted option though unimplemented feature).\n");
141                         break;
142                     case L'v':
143                         // UNIMPLEMENTED.
144                         ConPuts(StdErr, L"'v' option is FIXME (Accepted option though unimplemented feature).\n");
145                         bDoDispSeqComp = TRUE;
146                         break;
147                     default:
148 StopParsingAndShowUsageHelp:
149                         ConResPuts(StdErr, IDS_USAGE);
150                         return FALSE;
151                 }
152             }
153         }
154         else if (iswdigit(*argv[i]) != 0)
155         {
156             if (swscanf(argv[i], L"%lu", &Interval) != EOF)
157                 bLoopOutput = TRUE;
158             else
159                 return FALSE;
160         }
161     }
162 
163     return TRUE;
164 }
165 
DisplayOutput(VOID)166 BOOL DisplayOutput(VOID)
167 {
168     if (bNoOptions)
169     {
170         DisplayTableHeader();
171         return ShowTcpTable();
172     }
173 
174     if (bDoShowRouteTable)
175     {
176         if (_wsystem(L"route print") == -1)
177         {
178             ConResPuts(StdErr, IDS_ERROR_ROUTE);
179             return FALSE;
180         }
181         return TRUE;
182     }
183 
184     if (bDoShowEthStats)
185     {
186         ShowEthernetStatistics();
187         return TRUE;
188     }
189 
190     if (bDoShowProtoCons)
191     {
192         switch (Protocol)
193         {
194             case IP:
195                 if (bDoShowProtoStats)
196                     ShowIpStatistics();
197                 return TRUE;
198             case ICMP:
199                 if (bDoShowProtoStats)
200                     ShowIcmpStatistics();
201                 return TRUE;
202             case TCP:
203                 if (bDoShowProtoStats)
204                     ShowTcpStatistics();
205                 DisplayTableHeader();
206                 return ShowTcpTable();
207             case UDP:
208                 if (bDoShowProtoStats)
209                     ShowUdpStatistics();
210                 DisplayTableHeader();
211                 return (bDoShowAllCons ? ShowUdpTable() : TRUE);
212             default:
213                 break;
214         }
215     }
216     else if (bDoShowProtoStats)
217     {
218         ShowIpStatistics();
219         ShowIcmpStatistics();
220         ShowTcpStatistics();
221         ShowUdpStatistics();
222         return TRUE;
223     }
224     else
225     {
226         DisplayTableHeader();
227         if (ShowTcpTable() && bDoShowAllCons)
228             ShowUdpTable();
229     }
230 
231     return TRUE;
232 }
233 
ShowIpStatistics(VOID)234 VOID ShowIpStatistics(VOID)
235 {
236     MIB_IPSTATS IpStats;
237     DWORD dwRetVal;
238 
239     if ((dwRetVal = GetIpStatistics(&IpStats)) == NO_ERROR)
240     {
241         ConResPuts(StdOut, IDS_IP4_STAT_HEADER);
242         ConResPrintf(StdOut, IDS_IP_PACK_REC, IpStats.dwInReceives);
243         ConResPrintf(StdOut, IDS_IP_HEAD_REC_ERROR, IpStats.dwInHdrErrors);
244         ConResPrintf(StdOut, IDS_IP_ADDR_REC_ERROR, IpStats.dwInAddrErrors);
245         ConResPrintf(StdOut, IDS_IP_DATAG_FWD, IpStats.dwForwDatagrams);
246         ConResPrintf(StdOut, IDS_IP_UNKNOWN_PRO_REC, IpStats.dwInUnknownProtos);
247         ConResPrintf(StdOut, IDS_IP_REC_PACK_DISCARD, IpStats.dwInDiscards);
248         ConResPrintf(StdOut, IDS_IP_REC_PACK_DELIVER, IpStats.dwInDelivers);
249         ConResPrintf(StdOut, IDS_IP_OUT_REQUEST, IpStats.dwOutRequests);
250         ConResPrintf(StdOut, IDS_IP_ROUTE_DISCARD, IpStats.dwRoutingDiscards);
251         ConResPrintf(StdOut, IDS_IP_DISCARD_OUT_PACK, IpStats.dwOutDiscards);
252         ConResPrintf(StdOut, IDS_IP_OUT_PACKET_NO_ROUTE, IpStats.dwOutNoRoutes);
253         ConResPrintf(StdOut, IDS_IP_REASSEMBLE_REQUIRED, IpStats.dwReasmReqds);
254         ConResPrintf(StdOut, IDS_IP_REASSEMBLE_SUCCESS, IpStats.dwReasmOks);
255         ConResPrintf(StdOut, IDS_IP_REASSEMBLE_FAILURE, IpStats.dwReasmFails);
256         ConResPrintf(StdOut, IDS_IP_DATAG_FRAG_SUCCESS, IpStats.dwFragOks);
257         ConResPrintf(StdOut, IDS_IP_DATAG_FRAG_FAILURE, IpStats.dwFragFails);
258         ConResPrintf(StdOut, IDS_IP_DATAG_FRAG_CREATE, IpStats.dwFragCreates);
259     }
260     else
261     {
262         DoFormatMessage(dwRetVal);
263     }
264 }
265 
ShowIcmpStatistics(VOID)266 VOID ShowIcmpStatistics(VOID)
267 {
268     MIB_ICMP IcmpStats;
269     DWORD dwRetVal;
270 
271     if ((dwRetVal = GetIcmpStatistics(&IcmpStats)) == NO_ERROR)
272     {
273         ConResPuts(StdOut, IDS_ICMP4_STAT_HEADER);
274         ConResPuts(StdOut, IDS_ICMP_THEADER);
275         ConResPrintf(StdOut, IDS_ICMP_MSG,
276             IcmpStats.stats.icmpInStats.dwMsgs, IcmpStats.stats.icmpOutStats.dwMsgs);
277         ConResPrintf(StdOut, IDS_ICMP_ERROR,
278             IcmpStats.stats.icmpInStats.dwErrors, IcmpStats.stats.icmpOutStats.dwErrors);
279         ConResPrintf(StdOut, IDS_ICMP_DEST_UNREACH,
280             IcmpStats.stats.icmpInStats.dwDestUnreachs, IcmpStats.stats.icmpOutStats.dwDestUnreachs);
281         ConResPrintf(StdOut, IDS_ICMP_TIME_EXCEED,
282             IcmpStats.stats.icmpInStats.dwTimeExcds, IcmpStats.stats.icmpOutStats.dwTimeExcds);
283         ConResPrintf(StdOut, IDS_ICMP_PARAM_PROBLEM,
284             IcmpStats.stats.icmpInStats.dwParmProbs, IcmpStats.stats.icmpOutStats.dwParmProbs);
285         ConResPrintf(StdOut, IDS_ICMP_SRC_QUENCHES,
286             IcmpStats.stats.icmpInStats.dwSrcQuenchs, IcmpStats.stats.icmpOutStats.dwSrcQuenchs);
287         ConResPrintf(StdOut, IDS_ICMP_REDIRECT,
288             IcmpStats.stats.icmpInStats.dwRedirects, IcmpStats.stats.icmpOutStats.dwRedirects);
289         ConResPrintf(StdOut, IDS_ICMP_ECHO,
290             IcmpStats.stats.icmpInStats.dwEchos, IcmpStats.stats.icmpOutStats.dwEchos);
291         ConResPrintf(StdOut, IDS_ICMP_ECHO_REPLY,
292             IcmpStats.stats.icmpInStats.dwEchoReps, IcmpStats.stats.icmpOutStats.dwEchoReps);
293         ConResPrintf(StdOut, IDS_ICMP_TIMESTAMP,
294             IcmpStats.stats.icmpInStats.dwTimestamps, IcmpStats.stats.icmpOutStats.dwTimestamps);
295         ConResPrintf(StdOut, IDS_ICMP_TIMESTAMP_REPLY,
296             IcmpStats.stats.icmpInStats.dwTimestampReps, IcmpStats.stats.icmpOutStats.dwTimestampReps);
297         ConResPrintf(StdOut, IDS_ICMP_ADDRESSS_MASK,
298             IcmpStats.stats.icmpInStats.dwAddrMasks, IcmpStats.stats.icmpOutStats.dwAddrMasks);
299         ConResPrintf(StdOut, IDS_ICMP_ADDRESSS_MASK_REPLY,
300             IcmpStats.stats.icmpInStats.dwAddrMaskReps, IcmpStats.stats.icmpOutStats.dwAddrMaskReps);
301     }
302     else
303     {
304         DoFormatMessage(dwRetVal);
305     }
306 }
307 
ShowTcpStatistics(VOID)308 VOID ShowTcpStatistics(VOID)
309 {
310     MIB_TCPSTATS tcpStats;
311     DWORD dwRetVal;
312 
313     if ((dwRetVal = GetTcpStatistics(&tcpStats)) == NO_ERROR)
314     {
315         ConResPuts(StdOut, IDS_TCP4_HEADER);
316         ConResPrintf(StdOut, IDS_TCP_ACTIVE_OPEN, tcpStats.dwActiveOpens);
317         ConResPrintf(StdOut, IDS_TCP_PASS_OPEN, tcpStats.dwPassiveOpens);
318         ConResPrintf(StdOut, IDS_TCP_FAIL_CONNECT, tcpStats.dwAttemptFails);
319         ConResPrintf(StdOut, IDS_TCP_RESET_CONNECT, tcpStats.dwEstabResets);
320         ConResPrintf(StdOut, IDS_TCP_CURRENT_CONNECT, tcpStats.dwCurrEstab);
321         ConResPrintf(StdOut, IDS_TCP_SEG_RECEIVE, tcpStats.dwInSegs);
322         ConResPrintf(StdOut, IDS_TCP_SEG_SENT, tcpStats.dwOutSegs);
323         ConResPrintf(StdOut, IDS_TCP_SEG_RETRANSMIT, tcpStats.dwRetransSegs);
324     }
325     else
326     {
327         DoFormatMessage(dwRetVal);
328     }
329 }
330 
ShowUdpStatistics(VOID)331 VOID ShowUdpStatistics(VOID)
332 {
333     MIB_UDPSTATS udpStats;
334     DWORD dwRetVal;
335 
336     if ((dwRetVal = GetUdpStatistics(&udpStats)) == NO_ERROR)
337     {
338         ConResPuts(StdOut, IDS_UDP_IP4_HEADER);
339         ConResPrintf(StdOut, IDS_UDP_DATAG_RECEIVE, udpStats.dwInDatagrams);
340         ConResPrintf(StdOut, IDS_UDP_NO_PORT, udpStats.dwNoPorts);
341         ConResPrintf(StdOut, IDS_UDP_RECEIVE_ERROR, udpStats.dwInErrors);
342         ConResPrintf(StdOut, IDS_UDP_DATAG_SEND, udpStats.dwOutDatagrams);
343     }
344     else
345     {
346         DoFormatMessage(dwRetVal);
347     }
348 }
349 
ShowEthernetStatistics(VOID)350 VOID ShowEthernetStatistics(VOID)
351 {
352     PMIB_IFTABLE pIfTable;
353     DWORD dwSize = 0;
354     DWORD dwRetVal = 0;
355 
356     pIfTable = (MIB_IFTABLE*)HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IFTABLE));
357 
358     if (GetIfTable(pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
359     {
360         HeapFree(GetProcessHeap(), 0, pIfTable);
361         pIfTable = (MIB_IFTABLE*)HeapAlloc(GetProcessHeap(), 0, dwSize);
362 
363         if ((dwRetVal = GetIfTable(pIfTable, &dwSize, 0)) == NO_ERROR)
364         {
365             ConResPuts(StdOut, IDS_ETHERNET_INTERFACE_STAT);
366             ConResPuts(StdOut, IDS_ETHERNET_THEADER);
367             ConResPrintf(StdOut, IDS_ETHERNET_BYTES,
368                 pIfTable->table[0].dwInOctets, pIfTable->table[0].dwOutOctets);
369             ConResPrintf(StdOut, IDS_ETHERNET_UNICAST_PACKET,
370                 pIfTable->table[0].dwInUcastPkts, pIfTable->table[0].dwOutUcastPkts);
371             ConResPrintf(StdOut, IDS_ETHERNET_NON_UNICAST_PACKET,
372                 pIfTable->table[0].dwInNUcastPkts, pIfTable->table[0].dwOutNUcastPkts);
373             ConResPrintf(StdOut, IDS_ETHERNET_DISCARD,
374                 pIfTable->table[0].dwInDiscards, pIfTable->table[0].dwOutDiscards);
375             ConResPrintf(StdOut, IDS_ETHERNET_ERROR,
376                 pIfTable->table[0].dwInErrors, pIfTable->table[0].dwOutErrors);
377             ConResPrintf(StdOut, IDS_ETHERNET_UNKNOWN,
378                 pIfTable->table[0].dwInUnknownProtos);
379         }
380         else
381         {
382             DoFormatMessage(dwRetVal);
383         }
384     }
385     HeapFree(GetProcessHeap(), 0, pIfTable);
386 }
387 
ShowTcpTable(VOID)388 BOOL ShowTcpTable(VOID)
389 {
390     PMIB_TCPTABLE_OWNER_PID tcpTable;
391     DWORD error, dwSize;
392     DWORD i;
393     CHAR HostIp[HOSTNAMELEN], HostPort[PORTNAMELEN];
394     CHAR RemoteIp[HOSTNAMELEN], RemotePort[PORTNAMELEN];
395     CHAR Host[ADDRESSLEN];
396     CHAR Remote[ADDRESSLEN];
397     CHAR PID[64];
398 
399     /* Get the table of TCP endpoints */
400     dwSize = sizeof(MIB_TCPTABLE_OWNER_PID);
401     /* Should also work when we get new connections between 2 GetTcpTable()
402      * calls: */
403     do
404     {
405         tcpTable = (PMIB_TCPTABLE_OWNER_PID)HeapAlloc(GetProcessHeap(), 0, dwSize);
406         error = GetExtendedTcpTable(tcpTable, &dwSize, TRUE, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
407         if (error != NO_ERROR)
408             HeapFree(GetProcessHeap(), 0, tcpTable);
409     }
410     while (error == ERROR_INSUFFICIENT_BUFFER);
411 
412     if (error != NO_ERROR)
413     {
414         ConResPrintf(StdErr, IDS_ERROR_TCP_SNAPSHOT);
415         DoFormatMessage(error);
416         return FALSE;
417     }
418 
419     /* Dump the TCP table */
420     for (i = 0; i < tcpTable->dwNumEntries; i++)
421     {
422         /* If we aren't showing all connections, only display established, close wait
423          * and time wait. This is the default output for netstat */
424         if (bDoShowAllCons || (tcpTable->table[i].dwState ==  MIB_TCP_STATE_ESTAB)
425             || (tcpTable->table[i].dwState ==  MIB_TCP_STATE_CLOSE_WAIT)
426             || (tcpTable->table[i].dwState ==  MIB_TCP_STATE_TIME_WAIT))
427         {
428             /* I've split this up so it's easier to follow */
429             GetIpHostName(TRUE, tcpTable->table[i].dwLocalAddr, HostIp, sizeof(HostIp));
430             GetPortName(tcpTable->table[i].dwLocalPort, "tcp", HostPort, sizeof(HostPort));
431             sprintf(Host, "%s:%s", HostIp, HostPort);
432 
433             if (tcpTable->table[i].dwState ==  MIB_TCP_STATE_LISTEN)
434             {
435                 sprintf(Remote, "%s:0", HostIp);
436             }
437             else
438             {
439                 GetIpHostName(FALSE, tcpTable->table[i].dwRemoteAddr, RemoteIp, sizeof(RemoteIp));
440                 GetPortName(tcpTable->table[i].dwRemotePort, "tcp", RemotePort, sizeof(RemotePort));
441                 sprintf(Remote, "%s:%s", RemoteIp, RemotePort);
442             }
443 
444             if (bDoShowProcessId)
445             {
446                 sprintf(PID, "%ld", tcpTable->table[i].dwOwningPid);
447             }
448             else
449             {
450                 PID[0] = 0;
451             }
452 
453             ConPrintf(StdOut, L"  %-6s %-22S %-22S %-11s %S\n", L"TCP",
454                       Host, Remote, TcpState[tcpTable->table[i].dwState], PID);
455         }
456     }
457 
458     HeapFree(GetProcessHeap(), 0, tcpTable);
459     return TRUE;
460 }
461 
ShowUdpTable(VOID)462 BOOL ShowUdpTable(VOID)
463 {
464     PMIB_UDPTABLE_OWNER_PID udpTable;
465     DWORD error, dwSize;
466     DWORD i;
467     CHAR HostIp[HOSTNAMELEN], HostPort[PORTNAMELEN];
468     CHAR Host[ADDRESSLEN];
469     CHAR PID[64];
470 
471     /* Get the table of UDP endpoints */
472     dwSize = 0;
473     error = GetExtendedUdpTable(NULL, &dwSize, TRUE, AF_INET, UDP_TABLE_OWNER_PID, 0);
474     if (error != ERROR_INSUFFICIENT_BUFFER)
475     {
476         ConResPuts(StdErr, IDS_ERROR_UDP_ENDPOINT);
477         DoFormatMessage(error);
478         return FALSE;
479     }
480     udpTable = (PMIB_UDPTABLE_OWNER_PID)HeapAlloc(GetProcessHeap(), 0, dwSize);
481     error = GetExtendedUdpTable(udpTable, &dwSize, TRUE, AF_INET, UDP_TABLE_OWNER_PID, 0);
482     if (error)
483     {
484         ConResPuts(StdErr, IDS_ERROR_UDP_ENDPOINT_TABLE);
485         DoFormatMessage(error);
486         HeapFree(GetProcessHeap(), 0, udpTable);
487         return FALSE;
488     }
489 
490     /* Dump the UDP table */
491     for (i = 0; i < udpTable->dwNumEntries; i++)
492     {
493         /* I've split this up so it's easier to follow */
494         GetIpHostName(TRUE, udpTable->table[i].dwLocalAddr, HostIp, sizeof(HostIp));
495         GetPortName(udpTable->table[i].dwLocalPort, "udp", HostPort, sizeof(HostPort));
496 
497         sprintf(Host, "%s:%s", HostIp, HostPort);
498 
499         if (bDoShowProcessId)
500         {
501             sprintf(PID, "%ld", udpTable->table[i].dwOwningPid);
502         }
503         else
504         {
505             PID[0] = 0;
506         }
507 
508         ConPrintf(StdOut, L"  %-6s %-22S %-34s %S\n", L"UDP", Host, L"*:*", PID);
509     }
510 
511     HeapFree(GetProcessHeap(), 0, udpTable);
512     return TRUE;
513 }
514 
515 /*
516  * Translate port numbers into their text equivalent if there is one
517  */
518 PCHAR
GetPortName(UINT Port,PCSTR Proto,CHAR Name[],INT NameLen)519 GetPortName(UINT Port, PCSTR Proto, CHAR Name[], INT NameLen)
520 {
521     struct servent *pServent;
522 
523     if (bDoShowNumbers)
524     {
525         sprintf(Name, "%d", htons((WORD)Port));
526         return Name;
527     }
528     /* Try to translate to a name */
529     if ((pServent = getservbyport(Port, Proto)))
530         strcpy(Name, pServent->s_name);
531     else
532         sprintf(Name, "%d", htons((WORD)Port));
533     return Name;
534 }
535 
536 /*
537  * convert addresses into dotted decimal or hostname
538  */
539 PCHAR
GetIpHostName(BOOL Local,UINT IpAddr,CHAR Name[],INT NameLen)540 GetIpHostName(BOOL Local, UINT IpAddr, CHAR Name[], INT NameLen)
541 {
542 //  struct hostent *phostent;
543     UINT nIpAddr;
544 
545     /* display dotted decimal */
546     nIpAddr = htonl(IpAddr);
547     if (bDoShowNumbers) {
548         sprintf(Name, "%d.%d.%d.%d",
549             (nIpAddr >> 24) & 0xFF,
550             (nIpAddr >> 16) & 0xFF,
551             (nIpAddr >> 8) & 0xFF,
552             (nIpAddr) & 0xFF);
553         return Name;
554     }
555 
556     Name[0] = '\0';
557 
558     /* try to resolve the name */
559     if (!IpAddr) {
560         if (!Local) {
561             sprintf(Name, "%d.%d.%d.%d",
562                 (nIpAddr >> 24) & 0xFF,
563                 (nIpAddr >> 16) & 0xFF,
564                 (nIpAddr >> 8) & 0xFF,
565                 (nIpAddr) & 0xFF);
566         } else {
567             if (gethostname(Name, NameLen) != 0)
568                 DoFormatMessage(WSAGetLastError());
569         }
570     } else if (IpAddr == 0x0100007f) {
571         if (Local) {
572             if (gethostname(Name, NameLen) != 0)
573                 DoFormatMessage(WSAGetLastError());
574         } else {
575             strncpy(Name, "localhost", 10);
576         }
577 //  } else if (phostent = gethostbyaddr((char*)&ipaddr, sizeof(nipaddr), PF_INET)) {
578 //      strcpy(name, phostent->h_name);
579     } else {
580         sprintf(Name, "%d.%d.%d.%d",
581             ((nIpAddr >> 24) & 0x000000FF),
582             ((nIpAddr >> 16) & 0x000000FF),
583             ((nIpAddr >> 8) & 0x000000FF),
584             ((nIpAddr) & 0x000000FF));
585     }
586     return Name;
587 }
588 
589 /*
590  * Parse command line parameters and set any options
591  * Run display output, looping over set interval if a number is given
592  */
wmain(int argc,wchar_t * argv[])593 int wmain(int argc, wchar_t *argv[])
594 {
595     BOOL Success;
596     WSADATA wsaData;
597 
598     /* Initialize the Console Standard Streams */
599     ConInitStdStreams();
600 
601     if (!ParseCmdline(argc, argv))
602         return EXIT_FAILURE;
603 
604     if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
605     {
606         ConResPrintf(StdErr, IDS_ERROR_WSA_START, WSAGetLastError());
607         return EXIT_FAILURE;
608     }
609 
610     Success = DisplayOutput();
611     while (bLoopOutput && Success)
612     {
613         Sleep(Interval*1000);
614         Success = DisplayOutput();
615     }
616 
617     WSACleanup();
618     return (Success ? EXIT_SUCCESS : EXIT_FAILURE);
619 }
620