1
2
3
4
5 package oshi.software.os.windows;
6
7 import static com.sun.jna.platform.win32.IPHlpAPI.AF_INET;
8 import static com.sun.jna.platform.win32.IPHlpAPI.AF_INET6;
9 import static com.sun.jna.platform.win32.IPHlpAPI.TCP_TABLE_CLASS.TCP_TABLE_OWNER_PID_ALL;
10 import static com.sun.jna.platform.win32.IPHlpAPI.UDP_TABLE_CLASS.UDP_TABLE_OWNER_PID;
11 import static oshi.software.os.InternetProtocolStats.TcpState.CLOSED;
12 import static oshi.software.os.InternetProtocolStats.TcpState.CLOSE_WAIT;
13 import static oshi.software.os.InternetProtocolStats.TcpState.CLOSING;
14 import static oshi.software.os.InternetProtocolStats.TcpState.ESTABLISHED;
15 import static oshi.software.os.InternetProtocolStats.TcpState.FIN_WAIT_1;
16 import static oshi.software.os.InternetProtocolStats.TcpState.FIN_WAIT_2;
17 import static oshi.software.os.InternetProtocolStats.TcpState.LAST_ACK;
18 import static oshi.software.os.InternetProtocolStats.TcpState.LISTEN;
19 import static oshi.software.os.InternetProtocolStats.TcpState.SYN_RECV;
20 import static oshi.software.os.InternetProtocolStats.TcpState.SYN_SENT;
21 import static oshi.software.os.InternetProtocolStats.TcpState.TIME_WAIT;
22 import static oshi.software.os.InternetProtocolStats.TcpState.UNKNOWN;
23
24 import java.util.ArrayList;
25 import java.util.Collections;
26 import java.util.List;
27
28 import com.sun.jna.Memory;
29 import com.sun.jna.platform.win32.IPHlpAPI;
30 import com.sun.jna.platform.win32.IPHlpAPI.MIB_TCP6ROW_OWNER_PID;
31 import com.sun.jna.platform.win32.IPHlpAPI.MIB_TCP6TABLE_OWNER_PID;
32 import com.sun.jna.platform.win32.IPHlpAPI.MIB_TCPROW_OWNER_PID;
33 import com.sun.jna.platform.win32.IPHlpAPI.MIB_TCPTABLE_OWNER_PID;
34 import com.sun.jna.platform.win32.IPHlpAPI.MIB_UDP6ROW_OWNER_PID;
35 import com.sun.jna.platform.win32.IPHlpAPI.MIB_UDP6TABLE_OWNER_PID;
36 import com.sun.jna.platform.win32.IPHlpAPI.MIB_UDPROW_OWNER_PID;
37 import com.sun.jna.platform.win32.IPHlpAPI.MIB_UDPTABLE_OWNER_PID;
38 import com.sun.jna.platform.win32.VersionHelpers;
39 import com.sun.jna.platform.win32.WinError;
40
41 import oshi.annotation.concurrent.ThreadSafe;
42 import oshi.jna.ByRef.CloseableIntByReference;
43 import oshi.jna.Struct.CloseableMibTcpStats;
44 import oshi.jna.Struct.CloseableMibUdpStats;
45 import oshi.software.common.AbstractInternetProtocolStats;
46 import oshi.util.ParseUtil;
47
48
49
50
51 @ThreadSafe
52 public class WindowsInternetProtocolStats extends AbstractInternetProtocolStats {
53
54 private static final IPHlpAPI IPHLP = IPHlpAPI.INSTANCE;
55
56 private static final boolean IS_VISTA_OR_GREATER = VersionHelpers.IsWindowsVistaOrGreater();
57
58 @Override
59 public TcpStats getTCPv4Stats() {
60 try (CloseableMibTcpStats stats = new CloseableMibTcpStats()) {
61 IPHLP.GetTcpStatisticsEx(stats, AF_INET);
62 return new TcpStats(stats.dwCurrEstab, stats.dwActiveOpens, stats.dwPassiveOpens, stats.dwAttemptFails,
63 stats.dwEstabResets, stats.dwOutSegs, stats.dwInSegs, stats.dwRetransSegs, stats.dwInErrs,
64 stats.dwOutRsts);
65 }
66 }
67
68 @Override
69 public TcpStats getTCPv6Stats() {
70 try (CloseableMibTcpStats stats = new CloseableMibTcpStats()) {
71 IPHLP.GetTcpStatisticsEx(stats, AF_INET6);
72 return new TcpStats(stats.dwCurrEstab, stats.dwActiveOpens, stats.dwPassiveOpens, stats.dwAttemptFails,
73 stats.dwEstabResets, stats.dwOutSegs, stats.dwInSegs, stats.dwRetransSegs, stats.dwInErrs,
74 stats.dwOutRsts);
75 }
76 }
77
78 @Override
79 public UdpStats getUDPv4Stats() {
80 try (CloseableMibUdpStats stats = new CloseableMibUdpStats()) {
81 IPHLP.GetUdpStatisticsEx(stats, AF_INET);
82 return new UdpStats(stats.dwOutDatagrams, stats.dwInDatagrams, stats.dwNoPorts, stats.dwInErrors);
83 }
84 }
85
86 @Override
87 public UdpStats getUDPv6Stats() {
88 try (CloseableMibUdpStats stats = new CloseableMibUdpStats()) {
89 IPHLP.GetUdpStatisticsEx(stats, AF_INET6);
90 return new UdpStats(stats.dwOutDatagrams, stats.dwInDatagrams, stats.dwNoPorts, stats.dwInErrors);
91 }
92 }
93
94 @Override
95 public List<IPConnection> getConnections() {
96 if (IS_VISTA_OR_GREATER) {
97 List<IPConnection> conns = new ArrayList<>();
98 conns.addAll(queryTCPv4Connections());
99 conns.addAll(queryTCPv6Connections());
100 conns.addAll(queryUDPv4Connections());
101 conns.addAll(queryUDPv6Connections());
102 return conns;
103 }
104 return Collections.emptyList();
105 }
106
107 private static List<IPConnection> queryTCPv4Connections() {
108 List<IPConnection> conns = new ArrayList<>();
109
110 try (CloseableIntByReference sizePtr = new CloseableIntByReference()) {
111 int ret = IPHLP.GetExtendedTcpTable(null, sizePtr, false, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
112
113 int size = sizePtr.getValue();
114 Memory buf = new Memory(size);
115 do {
116 ret = IPHLP.GetExtendedTcpTable(buf, sizePtr, false, AF_INET, TCP_TABLE_OWNER_PID_ALL, 0);
117 if (ret == WinError.ERROR_INSUFFICIENT_BUFFER) {
118 size = sizePtr.getValue();
119 buf.close();
120 buf = new Memory(size);
121 }
122 } while (ret == WinError.ERROR_INSUFFICIENT_BUFFER);
123 MIB_TCPTABLE_OWNER_PID tcpTable = new MIB_TCPTABLE_OWNER_PID(buf);
124 for (int i = 0; i < tcpTable.dwNumEntries; i++) {
125 MIB_TCPROW_OWNER_PID row = tcpTable.table[i];
126 conns.add(new IPConnection("tcp4", ParseUtil.parseIntToIP(row.dwLocalAddr),
127 ParseUtil.bigEndian16ToLittleEndian(row.dwLocalPort), ParseUtil.parseIntToIP(row.dwRemoteAddr),
128 ParseUtil.bigEndian16ToLittleEndian(row.dwRemotePort), stateLookup(row.dwState), 0, 0,
129 row.dwOwningPid));
130 }
131 buf.close();
132 }
133 return conns;
134 }
135
136 private static List<IPConnection> queryTCPv6Connections() {
137 List<IPConnection> conns = new ArrayList<>();
138
139 try (CloseableIntByReference sizePtr = new CloseableIntByReference()) {
140 int ret = IPHLP.GetExtendedTcpTable(null, sizePtr, false, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0);
141
142 int size = sizePtr.getValue();
143 Memory buf = new Memory(size);
144 do {
145 ret = IPHLP.GetExtendedTcpTable(buf, sizePtr, false, AF_INET6, TCP_TABLE_OWNER_PID_ALL, 0);
146 if (ret == WinError.ERROR_INSUFFICIENT_BUFFER) {
147 size = sizePtr.getValue();
148 buf.close();
149 buf = new Memory(size);
150 }
151 } while (ret == WinError.ERROR_INSUFFICIENT_BUFFER);
152 MIB_TCP6TABLE_OWNER_PID tcpTable = new MIB_TCP6TABLE_OWNER_PID(buf);
153 for (int i = 0; i < tcpTable.dwNumEntries; i++) {
154 MIB_TCP6ROW_OWNER_PID row = tcpTable.table[i];
155 conns.add(new IPConnection("tcp6", row.LocalAddr, ParseUtil.bigEndian16ToLittleEndian(row.dwLocalPort),
156 row.RemoteAddr, ParseUtil.bigEndian16ToLittleEndian(row.dwRemotePort), stateLookup(row.State),
157 0, 0, row.dwOwningPid));
158 }
159 buf.close();
160 }
161 return conns;
162 }
163
164 private static List<IPConnection> queryUDPv4Connections() {
165 List<IPConnection> conns = new ArrayList<>();
166
167 try (CloseableIntByReference sizePtr = new CloseableIntByReference()) {
168 int ret = IPHLP.GetExtendedUdpTable(null, sizePtr, false, AF_INET, UDP_TABLE_OWNER_PID, 0);
169
170 int size = sizePtr.getValue();
171 Memory buf = new Memory(size);
172 do {
173 ret = IPHLP.GetExtendedUdpTable(buf, sizePtr, false, AF_INET, UDP_TABLE_OWNER_PID, 0);
174 if (ret == WinError.ERROR_INSUFFICIENT_BUFFER) {
175 size = sizePtr.getValue();
176 buf.close();
177 buf = new Memory(size);
178 }
179 } while (ret == WinError.ERROR_INSUFFICIENT_BUFFER);
180 MIB_UDPTABLE_OWNER_PID udpTable = new MIB_UDPTABLE_OWNER_PID(buf);
181 for (int i = 0; i < udpTable.dwNumEntries; i++) {
182 MIB_UDPROW_OWNER_PID row = udpTable.table[i];
183 conns.add(new IPConnection("udp4", ParseUtil.parseIntToIP(row.dwLocalAddr),
184 ParseUtil.bigEndian16ToLittleEndian(row.dwLocalPort), new byte[0], 0, TcpState.NONE, 0, 0,
185 row.dwOwningPid));
186 }
187 buf.close();
188 }
189 return conns;
190 }
191
192 private static List<IPConnection> queryUDPv6Connections() {
193 List<IPConnection> conns = new ArrayList<>();
194
195 try (CloseableIntByReference sizePtr = new CloseableIntByReference()) {
196 int ret = IPHLP.GetExtendedUdpTable(null, sizePtr, false, AF_INET6, UDP_TABLE_OWNER_PID, 0);
197
198 int size = sizePtr.getValue();
199 Memory buf = new Memory(size);
200 do {
201 ret = IPHLP.GetExtendedUdpTable(buf, sizePtr, false, AF_INET6, UDP_TABLE_OWNER_PID, 0);
202 if (ret == WinError.ERROR_INSUFFICIENT_BUFFER) {
203 size = sizePtr.getValue();
204 buf.close();
205 buf = new Memory(size);
206 }
207 } while (ret == WinError.ERROR_INSUFFICIENT_BUFFER);
208 MIB_UDP6TABLE_OWNER_PID udpTable = new MIB_UDP6TABLE_OWNER_PID(buf);
209 for (int i = 0; i < udpTable.dwNumEntries; i++) {
210 MIB_UDP6ROW_OWNER_PID row = udpTable.table[i];
211 conns.add(
212 new IPConnection("udp6", row.ucLocalAddr, ParseUtil.bigEndian16ToLittleEndian(row.dwLocalPort),
213 new byte[0], 0, TcpState.NONE, 0, 0, row.dwOwningPid));
214 }
215 }
216 return conns;
217 }
218
219 private static TcpState stateLookup(int state) {
220 switch (state) {
221 case 1:
222 case 12:
223 return CLOSED;
224 case 2:
225 return LISTEN;
226 case 3:
227 return SYN_SENT;
228 case 4:
229 return SYN_RECV;
230 case 5:
231 return ESTABLISHED;
232 case 6:
233 return FIN_WAIT_1;
234 case 7:
235 return FIN_WAIT_2;
236 case 8:
237 return CLOSE_WAIT;
238 case 9:
239 return CLOSING;
240 case 10:
241 return LAST_ACK;
242 case 11:
243 return TIME_WAIT;
244 default:
245 return UNKNOWN;
246 }
247 }
248 }