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