Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/programs/netstat/netstat.c
4389 views
1
/*
2
* Copyright 2011-2013 André Hentschel
3
*
4
* This library is free software; you can redistribute it and/or
5
* modify it under the terms of the GNU Lesser General Public
6
* License as published by the Free Software Foundation; either
7
* version 2.1 of the License, or (at your option) any later version.
8
*
9
* This library is distributed in the hope that it will be useful,
10
* but WITHOUT ANY WARRANTY; without even the implied warranty of
11
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12
* Lesser General Public License for more details.
13
*
14
* You should have received a copy of the GNU Lesser General Public
15
* License along with this library; if not, write to the Free Software
16
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17
*/
18
19
#include <stdio.h>
20
#include "netstat.h"
21
#include <winsock2.h>
22
#include <iphlpapi.h>
23
#include "wine/debug.h"
24
25
WINE_DEFAULT_DEBUG_CHANNEL(netstat);
26
27
static const WCHAR tcpstatesW[][16] = {
28
L"???",
29
L"CLOSED",
30
L"LISTENING",
31
L"SYN_SENT",
32
L"SYN_RCVD",
33
L"ESTABLISHED",
34
L"FIN_WAIT1",
35
L"FIN_WAIT2",
36
L"CLOSE_WAIT",
37
L"CLOSING",
38
L"LAST_ACK",
39
L"TIME_WAIT",
40
L"DELETE_TCB",
41
};
42
43
/* =========================================================================
44
* Output a unicode string. Ideally this will go to the console
45
* and hence required WriteConsoleW to output it, however if file i/o is
46
* redirected, it needs to be WriteFile'd using OEM (not ANSI) format
47
* ========================================================================= */
48
static int WINAPIV NETSTAT_wprintf(const WCHAR *format, ...)
49
{
50
static WCHAR *output_bufW = NULL;
51
static char *output_bufA = NULL;
52
static BOOL toConsole = TRUE;
53
static BOOL traceOutput = FALSE;
54
#define MAX_WRITECONSOLE_SIZE 65535
55
56
va_list parms;
57
DWORD nOut;
58
int len;
59
DWORD res = 0;
60
61
/*
62
* Allocate buffer to use when writing to console
63
* Note: Not freed - memory will be allocated once and released when
64
* netstat ends
65
*/
66
67
if (!output_bufW) output_bufW = HeapAlloc(GetProcessHeap(), 0,
68
MAX_WRITECONSOLE_SIZE*sizeof(WCHAR));
69
if (!output_bufW) {
70
WINE_FIXME("Out of memory - could not allocate 2 x 64 KB buffers\n");
71
return 0;
72
}
73
74
va_start(parms, format);
75
len = wvsprintfW(output_bufW, format, parms);
76
va_end(parms);
77
78
/* Try to write as unicode all the time we think it's a console */
79
if (toConsole) {
80
res = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
81
output_bufW, len, &nOut, NULL);
82
}
83
84
/* If writing to console has failed (ever) we assume it's file
85
i/o so convert to OEM codepage and output */
86
if (!res) {
87
BOOL usedDefaultChar = FALSE;
88
DWORD convertedChars;
89
90
toConsole = FALSE;
91
92
/*
93
* Allocate buffer to use when writing to file. Not freed, as above
94
*/
95
if (!output_bufA) output_bufA = HeapAlloc(GetProcessHeap(), 0,
96
MAX_WRITECONSOLE_SIZE);
97
if (!output_bufA) {
98
WINE_FIXME("Out of memory - could not allocate 2 x 64 KB buffers\n");
99
return 0;
100
}
101
102
/* Convert to OEM, then output */
103
convertedChars = WideCharToMultiByte(GetOEMCP(), 0, output_bufW,
104
len, output_bufA, MAX_WRITECONSOLE_SIZE,
105
"?", &usedDefaultChar);
106
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), output_bufA, convertedChars,
107
&nOut, FALSE);
108
}
109
110
/* Trace whether screen or console */
111
if (!traceOutput) {
112
WINE_TRACE("Writing to console? (%d)\n", toConsole);
113
traceOutput = TRUE;
114
}
115
return nOut;
116
}
117
118
static WCHAR *NETSTAT_load_message(UINT id) {
119
static WCHAR msg[2048];
120
121
if (!LoadStringW(GetModuleHandleW(NULL), id, msg, ARRAY_SIZE(msg))) {
122
WINE_FIXME("LoadString failed with %ld\n", GetLastError());
123
lstrcpyW(msg, L"Failed!");
124
}
125
return msg;
126
}
127
128
static WCHAR *NETSTAT_port_name(UINT port, WCHAR name[])
129
{
130
/* FIXME: can we get the name? */
131
swprintf(name, 32, L"%d", htons((WORD)port));
132
return name;
133
}
134
135
static WCHAR *NETSTAT_host_name(UINT ip, WCHAR name[])
136
{
137
UINT nip;
138
139
/* FIXME: can we get the name? */
140
nip = htonl(ip);
141
swprintf(name, MAX_HOSTNAME_LEN, L"%d.%d.%d.%d",
142
(nip >> 24) & 0xFF, (nip >> 16) & 0xFF, (nip >> 8) & 0xFF, (nip) & 0xFF);
143
return name;
144
}
145
146
static void NETSTAT_conn_header(void)
147
{
148
WCHAR local[22], remote[22], state[22];
149
NETSTAT_wprintf(L"\n%s\n\n", NETSTAT_load_message(IDS_TCP_ACTIVE_CONN));
150
lstrcpyW(local, NETSTAT_load_message(IDS_TCP_LOCAL_ADDR));
151
lstrcpyW(remote, NETSTAT_load_message(IDS_TCP_REMOTE_ADDR));
152
lstrcpyW(state, NETSTAT_load_message(IDS_TCP_STATE));
153
NETSTAT_wprintf(L" %-6s %-22s %-22s %s\n", NETSTAT_load_message(IDS_TCP_PROTO), local, remote, state);
154
}
155
156
static void NETSTAT_eth_stats(void)
157
{
158
PMIB_IFTABLE table;
159
DWORD err, size, i;
160
DWORD octets[2], ucastpkts[2], nucastpkts[2], discards[2], errors[2], unknown;
161
WCHAR recv[19];
162
163
size = sizeof(MIB_IFTABLE);
164
do
165
{
166
table = HeapAlloc(GetProcessHeap(), 0, size);
167
err = GetIfTable(table, &size, FALSE);
168
if (err != NO_ERROR) HeapFree(GetProcessHeap(), 0, table);
169
} while (err == ERROR_INSUFFICIENT_BUFFER);
170
171
if (err) return;
172
173
NETSTAT_wprintf(NETSTAT_load_message(IDS_ETH_STAT));
174
NETSTAT_wprintf(L"\n\n");
175
lstrcpyW(recv, NETSTAT_load_message(IDS_ETH_RECV));
176
NETSTAT_wprintf(L" %-19s %s\n\n", recv, NETSTAT_load_message(IDS_ETH_SENT));
177
178
octets[0] = octets[1] = 0;
179
ucastpkts[0] = ucastpkts[1] = 0;
180
nucastpkts[0] = nucastpkts[1] = 0;
181
discards[0] = discards[1] = 0;
182
errors[0] = errors[1] = 0;
183
unknown = 0;
184
185
for (i = 0; i < table->dwNumEntries; i++)
186
{
187
octets[0] += table->table[i].dwInOctets;
188
octets[1] += table->table[i].dwOutOctets;
189
ucastpkts[0] += table->table[i].dwInUcastPkts;
190
ucastpkts[1] += table->table[i].dwOutUcastPkts;
191
nucastpkts[0] += table->table[i].dwInNUcastPkts;
192
nucastpkts[1] += table->table[i].dwOutNUcastPkts;
193
discards[0] += table->table[i].dwInDiscards;
194
discards[1] += table->table[i].dwOutDiscards;
195
errors[0] += table->table[i].dwInErrors;
196
errors[1] += table->table[i].dwOutErrors;
197
unknown += table->table[i].dwInUnknownProtos;
198
}
199
200
NETSTAT_wprintf(L"%-20s %14lu %15lu\n", NETSTAT_load_message(IDS_ETH_BYTES), octets[0], octets[1]);
201
NETSTAT_wprintf(L"%-20s %14lu %15lu\n", NETSTAT_load_message(IDS_ETH_UNICAST), ucastpkts[0], ucastpkts[1]);
202
NETSTAT_wprintf(L"%-20s %14lu %15lu\n", NETSTAT_load_message(IDS_ETH_NUNICAST), nucastpkts[0], nucastpkts[1]);
203
NETSTAT_wprintf(L"%-20s %14lu %15lu\n", NETSTAT_load_message(IDS_ETH_DISCARDS), discards[0], discards[1]);
204
NETSTAT_wprintf(L"%-20s %14lu %15lu\n", NETSTAT_load_message(IDS_ETH_ERRORS), errors[0], errors[1]);
205
NETSTAT_wprintf(L"%-20s %14lu\n\n", NETSTAT_load_message(IDS_ETH_UNKNOWN), unknown);
206
207
HeapFree(GetProcessHeap(), 0, table);
208
}
209
210
static void NETSTAT_tcp_table(void)
211
{
212
PMIB_TCPTABLE table;
213
DWORD err, size, i;
214
WCHAR HostIp[MAX_HOSTNAME_LEN], HostPort[32];
215
WCHAR RemoteIp[MAX_HOSTNAME_LEN], RemotePort[32];
216
WCHAR Host[MAX_HOSTNAME_LEN + 32];
217
WCHAR Remote[MAX_HOSTNAME_LEN + 32];
218
219
size = sizeof(MIB_TCPTABLE);
220
do
221
{
222
table = HeapAlloc(GetProcessHeap(), 0, size);
223
err = GetTcpTable(table, &size, TRUE);
224
if (err != NO_ERROR) HeapFree(GetProcessHeap(), 0, table);
225
} while (err == ERROR_INSUFFICIENT_BUFFER);
226
227
if (err) return;
228
229
for (i = 0; i < table->dwNumEntries; i++)
230
{
231
if ((table->table[i].dwState == MIB_TCP_STATE_CLOSE_WAIT) ||
232
(table->table[i].dwState == MIB_TCP_STATE_ESTAB) ||
233
(table->table[i].dwState == MIB_TCP_STATE_TIME_WAIT))
234
{
235
NETSTAT_host_name(table->table[i].dwLocalAddr, HostIp);
236
NETSTAT_port_name(table->table[i].dwLocalPort, HostPort);
237
NETSTAT_host_name(table->table[i].dwRemoteAddr, RemoteIp);
238
NETSTAT_port_name(table->table[i].dwRemotePort, RemotePort);
239
240
swprintf(Host, ARRAY_SIZE(Host), L"%s:%s", HostIp, HostPort);
241
swprintf(Remote, ARRAY_SIZE(Remote), L"%s:%s", RemoteIp, RemotePort);
242
NETSTAT_wprintf(L" %-6s %-22s %-22s %s\n", L"TCP", Host, Remote, tcpstatesW[table->table[i].dwState]);
243
}
244
}
245
HeapFree(GetProcessHeap(), 0, table);
246
}
247
248
static void NETSTAT_tcp_stats(void)
249
{
250
MIB_TCPSTATS stats;
251
252
if (GetTcpStatistics(&stats) == NO_ERROR)
253
{
254
NETSTAT_wprintf(L"\n%s\n\n", NETSTAT_load_message(IDS_TCP_STAT));
255
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_ACTIVE_OPEN), stats.dwActiveOpens);
256
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_PASSIV_OPEN), stats.dwPassiveOpens);
257
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_FAILED_CONN), stats.dwAttemptFails);
258
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_RESET_CONN), stats.dwEstabResets);
259
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_CURR_CONN), stats.dwCurrEstab);
260
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_SEGM_RECV), stats.dwInSegs);
261
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_SEGM_SENT), stats.dwOutSegs);
262
NETSTAT_wprintf(L" %-35s = %lu\n", NETSTAT_load_message(IDS_TCP_SEGM_RETRAN), stats.dwRetransSegs);
263
}
264
}
265
266
static void NETSTAT_udp_table(void)
267
{
268
PMIB_UDPTABLE table;
269
DWORD err, size, i;
270
WCHAR HostIp[MAX_HOSTNAME_LEN], HostPort[32];
271
WCHAR Host[MAX_HOSTNAME_LEN + 32];
272
273
size = sizeof(MIB_UDPTABLE);
274
do
275
{
276
table = HeapAlloc(GetProcessHeap(), 0, size);
277
err = GetUdpTable(table, &size, TRUE);
278
if (err != NO_ERROR) HeapFree(GetProcessHeap(), 0, table);
279
} while (err == ERROR_INSUFFICIENT_BUFFER);
280
281
if (err) return;
282
283
for (i = 0; i < table->dwNumEntries; i++)
284
{
285
NETSTAT_host_name(table->table[i].dwLocalAddr, HostIp);
286
NETSTAT_port_name(table->table[i].dwLocalPort, HostPort);
287
288
swprintf(Host, ARRAY_SIZE(Host), L"%s:%s", HostIp, HostPort);
289
NETSTAT_wprintf(L" %-6s %-22s *:*\n", L"UDP", Host);
290
}
291
HeapFree(GetProcessHeap(), 0, table);
292
}
293
294
static void NETSTAT_udp_stats(void)
295
{
296
MIB_UDPSTATS stats;
297
298
if (GetUdpStatistics(&stats) == NO_ERROR)
299
{
300
NETSTAT_wprintf(L"\n%s\n\n", NETSTAT_load_message(IDS_UDP_STAT));
301
NETSTAT_wprintf(L" %-21s = %lu\n", NETSTAT_load_message(IDS_UDP_DGRAMS_RECV), stats.dwInDatagrams);
302
NETSTAT_wprintf(L" %-21s = %lu\n", NETSTAT_load_message(IDS_UDP_NO_PORTS), stats.dwNoPorts);
303
NETSTAT_wprintf(L" %-21s = %lu\n", NETSTAT_load_message(IDS_UDP_RECV_ERRORS), stats.dwInErrors);
304
NETSTAT_wprintf(L" %-21s = %lu\n", NETSTAT_load_message(IDS_UDP_DGRAMS_SENT), stats.dwOutDatagrams);
305
}
306
}
307
308
static NETSTATPROTOCOLS NETSTAT_get_protocol(WCHAR name[])
309
{
310
if (!wcsicmp(name, L"IP")) return PROT_IP;
311
if (!wcsicmp(name, L"IPv6")) return PROT_IPV6;
312
if (!wcsicmp(name, L"ICMP")) return PROT_ICMP;
313
if (!wcsicmp(name, L"ICMPv6")) return PROT_ICMPV6;
314
if (!wcsicmp(name, L"TCP")) return PROT_TCP;
315
if (!wcsicmp(name, L"TCPv6")) return PROT_TCPV6;
316
if (!wcsicmp(name, L"UDP")) return PROT_UDP;
317
if (!wcsicmp(name, L"UDPv6")) return PROT_UDPV6;
318
return PROT_UNKNOWN;
319
}
320
321
int __cdecl wmain(int argc, WCHAR *argv[])
322
{
323
WSADATA wsa_data;
324
BOOL output_stats = FALSE;
325
326
if (WSAStartup(MAKEWORD(2, 2), &wsa_data))
327
{
328
WINE_ERR("WSAStartup failed: %d\n", WSAGetLastError());
329
return 1;
330
}
331
332
if (argc == 1)
333
{
334
/* No options */
335
NETSTAT_conn_header();
336
NETSTAT_tcp_table();
337
return 0;
338
}
339
340
while (argv[1] && argv[1][0] == '-')
341
{
342
switch (argv[1][1])
343
{
344
case 'a':
345
NETSTAT_conn_header();
346
NETSTAT_tcp_table();
347
NETSTAT_udp_table();
348
return 0;
349
case 'e':
350
NETSTAT_eth_stats();
351
return 0;
352
case 's':
353
output_stats = TRUE;
354
break;
355
case 'p':
356
argv++; argc--;
357
if (argc == 1) return 1;
358
switch (NETSTAT_get_protocol(argv[1]))
359
{
360
case PROT_TCP:
361
if (output_stats)
362
NETSTAT_tcp_stats();
363
NETSTAT_conn_header();
364
NETSTAT_tcp_table();
365
break;
366
case PROT_UDP:
367
if (output_stats)
368
NETSTAT_udp_stats();
369
NETSTAT_conn_header();
370
NETSTAT_udp_table();
371
break;
372
default:
373
WINE_FIXME("Protocol not yet implemented: %s\n", debugstr_w(argv[1]));
374
}
375
return 0;
376
default:
377
WINE_FIXME("Unknown option: %s\n", debugstr_w(argv[1]));
378
return 1;
379
}
380
argv++; argc--;
381
}
382
383
if (output_stats)
384
{
385
NETSTAT_tcp_stats();
386
NETSTAT_udp_stats();
387
}
388
389
return 0;
390
}
391
392