2 * Copyright 2011-2013 André Hentschel
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.
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.
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
22 #include "wine/unicode.h"
23 #include "wine/debug.h"
25 WINE_DEFAULT_DEBUG_CHANNEL(netstat);
27 static const WCHAR ipW[] = {'I', 'P', 0};
28 static const WCHAR ipv6W[] = {'I', 'P', 'v', '6', 0};
29 static const WCHAR icmpW[] = {'I', 'C', 'M', 'P', 0};
30 static const WCHAR icmpv6W[] = {'I', 'C', 'M', 'P', 'v', '6', 0};
31 static const WCHAR tcpW[] = {'T', 'C', 'P', 0};
32 static const WCHAR tcpv6W[] = {'T', 'C', 'P', 'v', '6', 0};
33 static const WCHAR udpW[] = {'U', 'D', 'P', 0};
34 static const WCHAR udpv6W[] = {'U', 'D', 'P', 'v', '6', 0};
36 static const WCHAR fmtport[] = {'%', 'd', 0};
37 static const WCHAR fmtip[] = {'%', 'd', '.', '%', 'd', '.', '%', 'd', '.', '%', 'd', 0};
38 static const WCHAR fmtn[] = {'\n', 0};
39 static const WCHAR fmtnn[] = {'\n', '%', 's', '\n', 0};
40 static const WCHAR fmtcolon[] = {'%', 's', ':', '%', 's', 0};
41 static const WCHAR fmttcpout[] = {' ', ' ', '%', '-', '6', 's', ' ', '%', '-', '2', '2', 's', ' ', '%', '-', '2', '2', 's', ' ', '%', 's', '\n', 0};
42 static const WCHAR fmtudpout[] = {' ', ' ', '%', '-', '6', 's', ' ', '%', '-', '2', '2', 's', ' ', '*', ':', '*', '\n', 0};
44 /* =========================================================================
45 * Output a unicode string. Ideally this will go to the console
46 * and hence required WriteConsoleW to output it, however if file i/o is
47 * redirected, it needs to be WriteFile'd using OEM (not ANSI) format
48 * ========================================================================= */
49 static int __cdecl NETSTAT_wprintf(const WCHAR *format, ...)
51 static WCHAR *output_bufW = NULL;
52 static char *output_bufA = NULL;
53 static BOOL toConsole = TRUE;
54 static BOOL traceOutput = FALSE;
55 #define MAX_WRITECONSOLE_SIZE 65535
63 * Allocate buffer to use when writing to console
64 * Note: Not freed - memory will be allocated once and released when
68 if (!output_bufW) output_bufW = HeapAlloc(GetProcessHeap(), 0,
69 MAX_WRITECONSOLE_SIZE);
71 WINE_FIXME("Out of memory - could not allocate 2 x 64K buffers\n");
75 __ms_va_start(parms, format);
76 len = wvsprintfW(output_bufW, format, parms);
79 /* Try to write as unicode all the time we think its a console */
81 res = WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE),
82 output_bufW, len, &nOut, NULL);
85 /* If writing to console has failed (ever) we assume its file
86 i/o so convert to OEM codepage and output */
88 BOOL usedDefaultChar = FALSE;
94 * Allocate buffer to use when writing to file. Not freed, as above
96 if (!output_bufA) output_bufA = HeapAlloc(GetProcessHeap(), 0,
97 MAX_WRITECONSOLE_SIZE);
99 WINE_FIXME("Out of memory - could not allocate 2 x 64K buffers\n");
103 /* Convert to OEM, then output */
104 convertedChars = WideCharToMultiByte(GetConsoleOutputCP(), 0, output_bufW,
105 len, output_bufA, MAX_WRITECONSOLE_SIZE,
106 "?", &usedDefaultChar);
107 WriteFile(GetStdHandle(STD_OUTPUT_HANDLE), output_bufA, convertedChars,
111 /* Trace whether screen or console */
113 WINE_TRACE("Writing to console? (%d)\n", toConsole);
119 static WCHAR *NETSTAT_load_message(UINT id) {
120 static WCHAR msg[2048];
121 static const WCHAR failedW[] = {'F','a','i','l','e','d','!','\0'};
123 if (!LoadStringW(GetModuleHandleW(NULL), id, msg, sizeof(msg)/sizeof(WCHAR))) {
124 WINE_FIXME("LoadString failed with %d\n", GetLastError());
125 strcpyW(msg, failedW);
130 static WCHAR *NETSTAT_port_name(UINT port, WCHAR name[])
132 /* FIXME: can we get the name? */
133 sprintfW(name, fmtport, htons((WORD)port));
137 static WCHAR *NETSTAT_host_name(UINT ip, WCHAR name[])
141 /* FIXME: can we get the name? */
143 sprintfW(name, fmtip, (nip >> 24) & 0xFF, (nip >> 16) & 0xFF, (nip >> 8) & 0xFF, (nip) & 0xFF);
147 static void NETSTAT_tcp_header(void)
149 WCHAR local[22], remote[22], state[22];
150 NETSTAT_wprintf(fmtnn, NETSTAT_load_message(IDS_TCP_ACTIVE_CONN));
151 NETSTAT_wprintf(fmtn);
152 strcpyW(local, NETSTAT_load_message(IDS_TCP_LOCAL_ADDR));
153 strcpyW(remote, NETSTAT_load_message(IDS_TCP_REMOTE_ADDR));
154 strcpyW(state, NETSTAT_load_message(IDS_TCP_STATE));
155 NETSTAT_wprintf(fmttcpout, NETSTAT_load_message(IDS_TCP_PROTO), local, remote, state);
158 static void NETSTAT_tcp_table(void)
162 WCHAR HostIp[MAX_HOSTNAME_LEN], HostPort[32];
163 WCHAR RemoteIp[MAX_HOSTNAME_LEN], RemotePort[32];
164 WCHAR Host[MAX_HOSTNAME_LEN + 32];
165 WCHAR Remote[MAX_HOSTNAME_LEN + 32];
167 size = sizeof(MIB_TCPTABLE);
170 table = (PMIB_TCPTABLE)HeapAlloc(GetProcessHeap(), 0, size);
171 err = GetTcpTable(table, &size, TRUE);
172 if (err != NO_ERROR) HeapFree(GetProcessHeap(), 0, table);
173 } while (err == ERROR_INSUFFICIENT_BUFFER);
177 NETSTAT_tcp_header();
179 for (i = 0; i < table->dwNumEntries; i++)
181 if ((table->table[i].dwState == MIB_TCP_STATE_CLOSE_WAIT) ||
182 (table->table[i].dwState == MIB_TCP_STATE_ESTAB) ||
183 (table->table[i].dwState == MIB_TCP_STATE_TIME_WAIT))
185 NETSTAT_host_name(table->table[i].dwLocalAddr, HostIp);
186 NETSTAT_port_name(table->table[i].dwLocalPort, HostPort);
187 NETSTAT_host_name(table->table[i].dwRemoteAddr, RemoteIp);
188 NETSTAT_port_name(table->table[i].dwRemotePort, RemotePort);
190 sprintfW(Host, fmtcolon, HostIp, HostPort);
191 sprintfW(Remote, fmtcolon, RemoteIp, RemotePort);
192 NETSTAT_wprintf(fmttcpout, tcpW, Host, Remote, NETSTAT_load_message(table->table[i].dwState));
195 HeapFree(GetProcessHeap(), 0, table);
198 static void NETSTAT_udp_table(void)
202 WCHAR HostIp[MAX_HOSTNAME_LEN], HostPort[32];
203 WCHAR Host[MAX_HOSTNAME_LEN + 32];
205 size = sizeof(MIB_UDPTABLE);
208 table = (PMIB_UDPTABLE)HeapAlloc(GetProcessHeap(), 0, size);
209 err = GetUdpTable(table, &size, TRUE);
210 if (err != NO_ERROR) HeapFree(GetProcessHeap(), 0, table);
211 } while (err == ERROR_INSUFFICIENT_BUFFER);
215 NETSTAT_tcp_header();
217 for (i = 0; i < table->dwNumEntries; i++)
219 NETSTAT_host_name(table->table[i].dwLocalAddr, HostIp);
220 NETSTAT_port_name(table->table[i].dwLocalPort, HostPort);
222 sprintfW(Host, fmtcolon, HostIp, HostPort);
223 NETSTAT_wprintf(fmtudpout, udpW, Host);
225 HeapFree(GetProcessHeap(), 0, table);
228 static NETSTATPROTOCOLS NETSTAT_get_protocol(WCHAR name[])
230 if (!strcmpiW(name, ipW)) return PROT_IP;
231 if (!strcmpiW(name, ipv6W)) return PROT_IPV6;
232 if (!strcmpiW(name, icmpW)) return PROT_ICMP;
233 if (!strcmpiW(name, icmpv6W)) return PROT_ICMPV6;
234 if (!strcmpiW(name, tcpW)) return PROT_TCP;
235 if (!strcmpiW(name, tcpv6W)) return PROT_TCPV6;
236 if (!strcmpiW(name, udpW)) return PROT_UDP;
237 if (!strcmpiW(name, udpv6W)) return PROT_UDPV6;
241 int wmain(int argc, WCHAR *argv[])
245 if (WSAStartup(MAKEWORD(2, 2), &wsa_data))
247 WINE_ERR("WSAStartup failed: %d\n", WSAGetLastError());
258 while (argv[1] && argv[1][0] == '-')
264 if (argc == 1) return 1;
265 switch (NETSTAT_get_protocol(argv[1]))
274 WINE_FIXME("Protocol not yet implemented: %s\n", debugstr_w(argv[1]));
278 WINE_FIXME("Unknown option: %s\n", debugstr_w(argv[1]));