Sync up with trunk r61578.
[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: apps/utils/net/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 <tchar.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <iphlpapi.h>
26
27 #include "netstat.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 TCHAR TcpState[][32] = {
34 _T("???"),
35 _T("CLOSED"),
36 _T("LISTENING"),
37 _T("SYN_SENT"),
38 _T("SYN_RCVD"),
39 _T("ESTABLISHED"),
40 _T("FIN_WAIT1"),
41 _T("FIN_WAIT2"),
42 _T("CLOSE_WAIT"),
43 _T("CLOSING"),
44 _T("LAST_ACK"),
45 _T("TIME_WAIT"),
46 _T("DELETE_TCB")
47 };
48
49 /*
50 * format message string and display output
51 */
52 DWORD DoFormatMessage(DWORD ErrorCode)
53 {
54 LPVOID lpMsgBuf;
55 DWORD RetVal;
56
57 if ((RetVal = FormatMessage(
58 FORMAT_MESSAGE_ALLOCATE_BUFFER |
59 FORMAT_MESSAGE_FROM_SYSTEM |
60 FORMAT_MESSAGE_IGNORE_INSERTS,
61 NULL,
62 ErrorCode,
63 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), /* Default language */
64 (LPTSTR) &lpMsgBuf,
65 0,
66 NULL )))
67 {
68 _tprintf(_T("%s"), (LPTSTR)lpMsgBuf);
69
70 LocalFree(lpMsgBuf);
71 /* return number of TCHAR's stored in output buffer
72 * excluding '\0' - as FormatMessage does*/
73 return RetVal;
74 }
75 else
76 return 0;
77 }
78
79 /*
80 *
81 * Parse command line parameters and set any options
82 *
83 */
84 BOOL ParseCmdline(int argc, char* argv[])
85 {
86 INT i;
87
88 TCHAR Proto[5];
89
90 if ((argc == 1) || (_istdigit(*argv[1])))
91 bNoOptions = TRUE;
92
93 /* Parse command line for options we have been given. */
94 for (i = 1; i < argc; i++)
95 {
96 if ( (argc > 1)&&(argv[i][0] == '-') )
97 {
98 TCHAR c;
99
100 while ((c = *++argv[i]) != '\0')
101 {
102 switch (tolower(c))
103 {
104 case 'a' :
105 bDoShowAllCons = TRUE;
106 break;
107 case 'b' :
108 bDoShowProcName = TRUE;
109 break;
110 case 'e' :
111 bDoShowEthStats = TRUE;
112 break;
113 case 'n' :
114 bDoShowNumbers = TRUE;
115 break;
116 case 's' :
117 bDoShowProtoStats = TRUE;
118 break;
119 case 'p' :
120 bDoShowProtoCons = TRUE;
121
122 strncpy(Proto, (++argv)[i], sizeof(Proto));
123 if (!_tcsicmp( "IP", Proto ))
124 Protocol = IP;
125 else if (!_tcsicmp( "ICMP", Proto ))
126 Protocol = ICMP;
127 else if (!_tcsicmp( "TCP", Proto ))
128 Protocol = TCP;
129 else if (!_tcsicmp( "UDP", Proto ))
130 Protocol = UDP;
131 else
132 {
133 Usage();
134 return EXIT_FAILURE;
135 }
136 --i; /* move pointer back down to previous argv */
137 break;
138 case 'r' :
139 bDoShowRouteTable = TRUE;
140 break;
141 case 'v' :
142 _tprintf(_T("got v\n"));
143 bDoDispSeqComp = TRUE;
144 break;
145 default :
146 Usage();
147 return EXIT_FAILURE;
148 }
149 }
150 }
151 else if (_istdigit(*argv[i]))
152 {
153 if (_stscanf(argv[i], "%lu", &Interval) != EOF)
154 bLoopOutput = TRUE;
155 else
156 return EXIT_FAILURE;
157 }
158 // else
159 // {
160 // Usage();
161 // EXIT_FAILURE;
162 // }
163 }
164
165 return EXIT_SUCCESS;
166 }
167
168 /*
169 * Simulate Microsofts netstat utility output
170 */
171 BOOL DisplayOutput()
172 {
173 if (bNoOptions)
174 {
175 _tprintf(_T("\n Proto Local Address Foreign Address State\n"));
176 ShowTcpTable();
177 return EXIT_SUCCESS;
178 }
179
180 if (bDoShowRouteTable)
181 {
182 /* mingw doesn't have lib for _tsystem */
183 if (system("route print") == -1)
184 {
185 _tprintf(_T("cannot find 'route.exe'\n"));
186 return EXIT_FAILURE;
187 }
188 return EXIT_SUCCESS;
189 }
190
191 if (bDoShowEthStats)
192 {
193 ShowEthernetStatistics();
194 return EXIT_SUCCESS;
195 }
196
197 if (bDoShowProtoCons)
198 {
199 switch (Protocol)
200 {
201 case IP :
202 if (bDoShowProtoStats)
203 {
204 ShowIpStatistics();
205 return EXIT_SUCCESS;
206 }
207 break;
208 case ICMP :
209 if (bDoShowProtoStats)
210 {
211 ShowIcmpStatistics();
212 return EXIT_SUCCESS;
213 }
214 break;
215 case TCP :
216 if (bDoShowProtoStats)
217 ShowTcpStatistics();
218 _tprintf(_T("\nActive Connections\n"));
219 _tprintf(_T("\n Proto Local Address Foreign Address State\n"));
220 ShowTcpTable();
221 break;
222 case UDP :
223 if (bDoShowProtoStats)
224 ShowUdpStatistics();
225 _tprintf(_T("\nActive Connections\n"));
226 _tprintf(_T("\n Proto Local Address Foreign Address State\n"));
227 ShowUdpTable();
228 break;
229 default :
230 break;
231 }
232 }
233 else if (bDoShowProtoStats)
234 {
235 ShowIpStatistics();
236 ShowIcmpStatistics();
237 ShowTcpStatistics();
238 ShowUdpStatistics();
239 return EXIT_SUCCESS;
240 }
241 else
242 {
243 _tprintf(_T("\nActive Connections\n"));
244 _tprintf(_T("\n Proto Local Address Foreign Address State\n"));
245 ShowTcpTable();
246 if (bDoShowAllCons)
247 ShowUdpTable();
248 }
249 return EXIT_SUCCESS;
250 }
251
252 VOID ShowIpStatistics()
253 {
254 PMIB_IPSTATS pIpStats;
255 DWORD dwRetVal;
256
257 pIpStats = (MIB_IPSTATS*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IPSTATS));
258
259 if ((dwRetVal = GetIpStatistics(pIpStats)) == NO_ERROR)
260 {
261 _tprintf(_T("\nIPv4 Statistics\n\n"));
262 _tprintf(_T(" %-34s = %lu\n"), _T("Packets Received"), pIpStats->dwInReceives);
263 _tprintf(_T(" %-34s = %lu\n"), _T("Received Header Errors"), pIpStats->dwInHdrErrors);
264 _tprintf(_T(" %-34s = %lu\n"), _T("Received Address Errors"), pIpStats->dwInAddrErrors);
265 _tprintf(_T(" %-34s = %lu\n"), _T("Datagrams Forwarded"), pIpStats->dwForwDatagrams);
266 _tprintf(_T(" %-34s = %lu\n"), _T("Unknown Protocols Received"), pIpStats->dwInUnknownProtos);
267 _tprintf(_T(" %-34s = %lu\n"), _T("Received Packets Discarded"), pIpStats->dwInDiscards);
268 _tprintf(_T(" %-34s = %lu\n"), _T("Received Packets Delivered"), pIpStats->dwInDelivers);
269 _tprintf(_T(" %-34s = %lu\n"), _T("Output Requests"), pIpStats->dwOutRequests);
270 _tprintf(_T(" %-34s = %lu\n"), _T("Routing Discards"), pIpStats->dwRoutingDiscards);
271 _tprintf(_T(" %-34s = %lu\n"), _T("Discarded Output Packets"), pIpStats->dwOutDiscards);
272 _tprintf(_T(" %-34s = %lu\n"), _T("Output Packets No Route"), pIpStats->dwOutNoRoutes);
273 _tprintf(_T(" %-34s = %lu\n"), _T("Reassembly Required"), pIpStats->dwReasmReqds);
274 _tprintf(_T(" %-34s = %lu\n"), _T("Reassembly Succesful"), pIpStats->dwReasmOks);
275 _tprintf(_T(" %-34s = %lu\n"), _T("Reassembly Failures"), pIpStats->dwReasmFails);
276 // _tprintf(_T(" %-34s = %lu\n"), _T("Datagrams succesfully fragmented"), NULL); /* FIXME: what is this one? */
277 _tprintf(_T(" %-34s = %lu\n"), _T("Datagrams Failing Fragmentation"), pIpStats->dwFragFails);
278 _tprintf(_T(" %-34s = %lu\n"), _T("Fragments Created"), pIpStats->dwFragCreates);
279 }
280 else
281 DoFormatMessage(dwRetVal);
282
283 HeapFree(GetProcessHeap(), 0, pIpStats);
284 }
285
286 VOID ShowIcmpStatistics()
287 {
288 PMIB_ICMP pIcmpStats;
289 DWORD dwRetVal;
290
291 pIcmpStats = (MIB_ICMP*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_ICMP));
292
293 if ((dwRetVal = GetIcmpStatistics(pIcmpStats)) == NO_ERROR)
294 {
295 _tprintf(_T("\nICMPv4 Statistics\n\n"));
296 _tprintf(_T(" Received Sent\n"));
297 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Messages"),
298 pIcmpStats->stats.icmpInStats.dwMsgs, pIcmpStats->stats.icmpOutStats.dwMsgs);
299 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Errors"),
300 pIcmpStats->stats.icmpInStats.dwErrors, pIcmpStats->stats.icmpOutStats.dwErrors);
301 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Destination Unreachable"),
302 pIcmpStats->stats.icmpInStats.dwDestUnreachs, pIcmpStats->stats.icmpOutStats.dwDestUnreachs);
303 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Time Exceeded"),
304 pIcmpStats->stats.icmpInStats.dwTimeExcds, pIcmpStats->stats.icmpOutStats.dwTimeExcds);
305 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Parameter Problems"),
306 pIcmpStats->stats.icmpInStats.dwParmProbs, pIcmpStats->stats.icmpOutStats.dwParmProbs);
307 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Source Quenches"),
308 pIcmpStats->stats.icmpInStats.dwSrcQuenchs, pIcmpStats->stats.icmpOutStats.dwSrcQuenchs);
309 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Redirects"),
310 pIcmpStats->stats.icmpInStats.dwRedirects, pIcmpStats->stats.icmpOutStats.dwRedirects);
311 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Echos"),
312 pIcmpStats->stats.icmpInStats.dwEchos, pIcmpStats->stats.icmpOutStats.dwEchos);
313 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Echo Replies"),
314 pIcmpStats->stats.icmpInStats.dwEchoReps, pIcmpStats->stats.icmpOutStats.dwEchoReps);
315 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Timestamps"),
316 pIcmpStats->stats.icmpInStats.dwTimestamps, pIcmpStats->stats.icmpOutStats.dwTimestamps);
317 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Timestamp Replies"),
318 pIcmpStats->stats.icmpInStats.dwTimestampReps, pIcmpStats->stats.icmpOutStats.dwTimestampReps);
319 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Address Masks"),
320 pIcmpStats->stats.icmpInStats.dwAddrMasks, pIcmpStats->stats.icmpOutStats.dwAddrMasks);
321 _tprintf(_T(" %-25s %-11lu %lu\n"), _T("Address Mask Replies"),
322 pIcmpStats->stats.icmpInStats.dwAddrMaskReps, pIcmpStats->stats.icmpOutStats.dwAddrMaskReps);
323 }
324 else
325 DoFormatMessage(dwRetVal);
326
327 HeapFree(GetProcessHeap(), 0, pIcmpStats);
328
329 }
330
331 VOID ShowTcpStatistics()
332 {
333 PMIB_TCPSTATS pTcpStats;
334 DWORD dwRetVal;
335
336 pTcpStats = (MIB_TCPSTATS*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_TCPSTATS));
337
338 if ((dwRetVal = GetTcpStatistics(pTcpStats)) == NO_ERROR)
339 {
340 _tprintf(_T("\nTCP Statistics for IPv4\n\n"));
341 _tprintf(_T(" %-35s = %lu\n"), _T("Active Opens"), pTcpStats->dwActiveOpens);
342 _tprintf(_T(" %-35s = %lu\n"), _T("Passive Opens"), pTcpStats->dwPassiveOpens);
343 _tprintf(_T(" %-35s = %lu\n"), _T("Failed Connection Attempts"), pTcpStats->dwAttemptFails);
344 _tprintf(_T(" %-35s = %lu\n"), _T("Reset Connections"), pTcpStats->dwEstabResets);
345 _tprintf(_T(" %-35s = %lu\n"), _T("Current Connections"), pTcpStats->dwCurrEstab);
346 _tprintf(_T(" %-35s = %lu\n"), _T("Segments Received"), pTcpStats->dwInSegs);
347 _tprintf(_T(" %-35s = %lu\n"), _T("Segments Sent"), pTcpStats->dwOutSegs);
348 _tprintf(_T(" %-35s = %lu\n"), _T("Segments Retransmitted"), pTcpStats->dwRetransSegs);
349 }
350 else
351 DoFormatMessage(dwRetVal);
352
353 HeapFree(GetProcessHeap(), 0, pTcpStats);
354 }
355
356 VOID ShowUdpStatistics()
357 {
358 PMIB_UDPSTATS pUdpStats;
359 DWORD dwRetVal;
360
361 pUdpStats = (MIB_UDPSTATS*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_UDPSTATS));
362
363 if ((dwRetVal = GetUdpStatistics(pUdpStats)) == NO_ERROR)
364 {
365 _tprintf(_T("\nUDP Statistics for IPv4\n\n"));
366 _tprintf(_T(" %-21s = %lu\n"), _T("Datagrams Received"), pUdpStats->dwInDatagrams);
367 _tprintf(_T(" %-21s = %lu\n"), _T("No Ports"), pUdpStats->dwNoPorts);
368 _tprintf(_T(" %-21s = %lu\n"), _T("Receive Errors"), pUdpStats->dwInErrors);
369 _tprintf(_T(" %-21s = %lu\n"), _T("Datagrams Sent"), pUdpStats->dwOutDatagrams);
370 }
371 else
372 DoFormatMessage(dwRetVal);
373
374 HeapFree(GetProcessHeap(), 0, pUdpStats);
375 }
376
377 VOID ShowEthernetStatistics()
378 {
379 PMIB_IFTABLE pIfTable;
380 DWORD dwSize = 0;
381 DWORD dwRetVal = 0;
382
383 pIfTable = (MIB_IFTABLE*) HeapAlloc(GetProcessHeap(), 0, sizeof(MIB_IFTABLE));
384
385 if (GetIfTable(pIfTable, &dwSize, 0) == ERROR_INSUFFICIENT_BUFFER)
386 {
387 HeapFree(GetProcessHeap(), 0, pIfTable);
388 pIfTable = (MIB_IFTABLE*) HeapAlloc(GetProcessHeap(), 0, dwSize);
389
390 if ((dwRetVal = GetIfTable(pIfTable, &dwSize, 0)) == NO_ERROR)
391 {
392 _tprintf(_T("Interface Statistics\n\n"));
393 _tprintf(_T(" Received Sent\n\n"));
394 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Bytes"),
395 pIfTable->table[0].dwInOctets, pIfTable->table[0].dwOutOctets);
396 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Unicast packets"),
397 pIfTable->table[0].dwInUcastPkts, pIfTable->table[0].dwOutUcastPkts);
398 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Non-unicast packets"),
399 pIfTable->table[0].dwInNUcastPkts, pIfTable->table[0].dwOutNUcastPkts);
400 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Discards"),
401 pIfTable->table[0].dwInDiscards, pIfTable->table[0].dwOutDiscards);
402 _tprintf(_T("%-20s %14lu %15lu\n"), _T("Errors"),
403 pIfTable->table[0].dwInErrors, pIfTable->table[0].dwOutErrors);
404 _tprintf(_T("%-20s %14lu\n"), _T("Unknown Protocols"),
405 pIfTable->table[0].dwInUnknownProtos);
406 }
407 else
408 DoFormatMessage(dwRetVal);
409 }
410 HeapFree(GetProcessHeap(), 0, pIfTable);
411 }
412
413 VOID ShowTcpTable()
414 {
415 PMIB_TCPTABLE tcpTable;
416 DWORD error, dwSize;
417 DWORD i;
418 CHAR HostIp[HOSTNAMELEN], HostPort[PORTNAMELEN];
419 CHAR RemoteIp[HOSTNAMELEN], RemotePort[PORTNAMELEN];
420 CHAR Host[ADDRESSLEN];
421 CHAR Remote[ADDRESSLEN];
422
423 /* Get the table of TCP endpoints */
424 dwSize = sizeof (MIB_TCPTABLE);
425 /* Should also work when we get new connections between 2 GetTcpTable()
426 * calls: */
427 do
428 {
429 tcpTable = (PMIB_TCPTABLE) HeapAlloc(GetProcessHeap(), 0, dwSize);
430 error = GetTcpTable(tcpTable, &dwSize, TRUE);
431 if ( error != NO_ERROR )
432 HeapFree(GetProcessHeap(), 0, tcpTable);
433 }
434 while ( error == ERROR_INSUFFICIENT_BUFFER );
435
436 if (error != NO_ERROR)
437 {
438 printf("Failed to snapshot TCP endpoints.\n");
439 DoFormatMessage(error);
440 exit(EXIT_FAILURE);
441 }
442
443 /* Dump the TCP table */
444 for (i = 0; i < tcpTable->dwNumEntries; i++)
445 {
446 /* If we aren't showing all connections, only display established, close wait
447 * and time wait. This is the default output for netstat */
448 if (bDoShowAllCons || (tcpTable->table[i].dwState == MIB_TCP_STATE_ESTAB)
449 || (tcpTable->table[i].dwState == MIB_TCP_STATE_CLOSE_WAIT)
450 || (tcpTable->table[i].dwState == MIB_TCP_STATE_TIME_WAIT))
451 {
452 /* I've split this up so it's easier to follow */
453 GetIpHostName(TRUE, tcpTable->table[i].dwLocalAddr, HostIp, HOSTNAMELEN);
454 GetPortName(tcpTable->table[i].dwLocalPort, "tcp", HostPort, PORTNAMELEN);
455 GetIpHostName(FALSE, tcpTable->table[i].dwRemoteAddr, RemoteIp, HOSTNAMELEN);
456 GetPortName(tcpTable->table[i].dwRemotePort, "tcp", RemotePort, PORTNAMELEN);
457
458 sprintf(Host, "%s:%s", HostIp, HostPort);
459 sprintf(Remote, "%s:%s", RemoteIp, RemotePort);
460
461 _tprintf(_T(" %-6s %-22s %-22s %s\n"), _T("TCP"),
462 Host, Remote, TcpState[tcpTable->table[i].dwState]);
463 }
464 }
465 HeapFree(GetProcessHeap(), 0, tcpTable);
466 }
467
468 VOID ShowUdpTable()
469 {
470 PMIB_UDPTABLE udpTable;
471 DWORD error, dwSize;
472 DWORD i;
473 CHAR HostIp[HOSTNAMELEN], HostPort[PORTNAMELEN];
474 CHAR Host[ADDRESSLEN];
475
476 /* Get the table of UDP endpoints */
477 dwSize = 0;
478 error = GetUdpTable(NULL, &dwSize, TRUE);
479 if (error != ERROR_INSUFFICIENT_BUFFER)
480 {
481 printf("Failed to snapshot UDP endpoints.\n");
482 DoFormatMessage(error);
483 exit(EXIT_FAILURE);
484 }
485 udpTable = (PMIB_UDPTABLE) HeapAlloc(GetProcessHeap(), 0, dwSize);
486 error = GetUdpTable(udpTable, &dwSize, TRUE);
487 if (error)
488 {
489 printf("Failed to snapshot UDP endpoints table.\n");
490 DoFormatMessage(error);
491 HeapFree(GetProcessHeap(), 0, udpTable);
492 exit(EXIT_FAILURE);
493 }
494
495 /* Dump the UDP table */
496 for (i = 0; i < udpTable->dwNumEntries; i++)
497 {
498
499 /* I've split this up so it's easier to follow */
500 GetIpHostName(TRUE, udpTable->table[i].dwLocalAddr, HostIp, HOSTNAMELEN);
501 GetPortName(udpTable->table[i].dwLocalPort, "tcp", HostPort, PORTNAMELEN);
502
503 sprintf(Host, "%s:%s", HostIp, HostPort);
504
505 _tprintf(_T(" %-6s %-22s %-22s\n"), _T("UDP"), Host, _T("*:*"));
506 }
507
508 HeapFree(GetProcessHeap(), 0, udpTable);
509 }
510
511 /*
512 * Translate port numbers into their text equivalent if there is one
513 */
514 PCHAR
515 GetPortName(UINT Port, PCSTR Proto, CHAR Name[], INT NameLen)
516 {
517 struct servent *pSrvent;
518
519 if (bDoShowNumbers)
520 {
521 sprintf(Name, "%d", htons((WORD)Port));
522 return Name;
523 }
524 /* Try to translate to a name */
525 if ((pSrvent = getservbyport(Port, Proto)))
526 strcpy(Name, pSrvent->s_name );
527 else
528 sprintf(Name, "%d", htons((WORD)Port));
529 return Name;
530 }
531
532 /*
533 * convert addresses into dotted decimal or hostname
534 */
535 PCHAR
536 GetIpHostName(BOOL Local, UINT IpAddr, CHAR Name[], int NameLen)
537 {
538 // struct hostent *phostent;
539 UINT nIpAddr;
540
541 /* display dotted decimal */
542 nIpAddr = htonl(IpAddr);
543 if (bDoShowNumbers) {
544 sprintf(Name, "%d.%d.%d.%d",
545 (nIpAddr >> 24) & 0xFF,
546 (nIpAddr >> 16) & 0xFF,
547 (nIpAddr >> 8) & 0xFF,
548 (nIpAddr) & 0xFF);
549 return Name;
550 }
551
552 Name[0] = _T('\0');
553
554 /* try to resolve the name */
555 if (!IpAddr) {
556 if (!Local) {
557 sprintf(Name, "%d.%d.%d.%d",
558 (nIpAddr >> 24) & 0xFF,
559 (nIpAddr >> 16) & 0xFF,
560 (nIpAddr >> 8) & 0xFF,
561 (nIpAddr) & 0xFF);
562 } else {
563 if (gethostname(Name, NameLen) != 0)
564 DoFormatMessage(WSAGetLastError());
565 }
566 } else if (IpAddr == 0x0100007f) {
567 if (Local) {
568 if (gethostname(Name, NameLen) != 0)
569 DoFormatMessage(WSAGetLastError());
570 } else {
571 _tcsncpy(Name, _T("localhost"), 10);
572 }
573 // } else if (phostent = gethostbyaddr((char*)&ipaddr, sizeof(nipaddr), PF_INET)) {
574 // strcpy(name, phostent->h_name);
575 } else {
576 sprintf(Name, "%d.%d.%d.%d",
577 ((nIpAddr >> 24) & 0x000000FF),
578 ((nIpAddr >> 16) & 0x000000FF),
579 ((nIpAddr >> 8) & 0x000000FF),
580 ((nIpAddr) & 0x000000FF));
581 }
582 return Name;
583 }
584
585 VOID Usage()
586 {
587 _tprintf(_T("\nDisplays current TCP/IP protocol statistics and network connections.\n\n"
588 "NETSTAT [-a] [-e] [-n] [-s] [-p proto] [-r] [interval]\n\n"
589 " -a Displays all connections and listening ports.\n"
590 " -e Displays Ethernet statistics. May be combined with -s\n"
591 " option\n"
592 " -n Displays address and port numbers in numeric form.\n"
593 " -p proto Shows connections for protocol 'proto' TCP or UDP.\n"
594 " If used with the -s option to display\n"
595 " per-protocol statistics, 'proto' may be TCP, UDP, or IP.\n"
596 " -r Displays the current routing table.\n"
597 " -s Displays per-protocol statistics. By default, Statistics are\n"
598 " shown for IP, ICMP, TCP and UDP;\n"
599 " the -p option may be used to specify a subset of the default.\n"
600 " interval Redisplays selected statistics every 'interval' seconds.\n"
601 " Press CTRL+C to stop redisplaying. By default netstat will\n"
602 " print the current information only once.\n"));
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 main(int argc, char *argv[])
612 {
613 WSADATA wsaData;
614
615 if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
616 {
617 _tprintf(_T("WSAStartup() failed : %d\n"), WSAGetLastError());
618 return -1;
619 }
620
621 if (ParseCmdline(argc, argv))
622 return -1;
623
624 if (bLoopOutput)
625 {
626 while (1)
627 {
628 if (DisplayOutput())
629 return -1;
630 Sleep(Interval*1000);
631 }
632 }
633
634 if (DisplayOutput())
635 return -1;
636 else
637 return 0;
638 }