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