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