1 /*
2 * Copyright 2020-2023 The OSHI Project Contributors
3 * SPDX-License-Identifier: MIT
4 */
5 package oshi.software.os;
6
7 import java.net.InetAddress;
8 import java.net.UnknownHostException;
9 import java.util.Arrays;
10 import java.util.List;
11
12 import oshi.annotation.concurrent.Immutable;
13 import oshi.annotation.concurrent.ThreadSafe;
14
15 /**
16 * Includes key statistics of TCP and UDP protocols
17 */
18 @ThreadSafe
19 public interface InternetProtocolStats {
20
21 /**
22 * Get the TCP stats for IPv4 connections.
23 * <p>
24 * On macOS connection information requires elevated permissions. Without elevatd permissions, segment data is
25 * estimated.
26 *
27 * @return a {@link TcpStats} object encapsulating the stats.
28 */
29 TcpStats getTCPv4Stats();
30
31 /**
32 * Get the TCP stats for IPv6 connections, if available. If not available separately, these may be 0 and included in
33 * IPv4 connections.
34 *
35 * @return a {@link TcpStats} object encapsulating the stats.
36 */
37 TcpStats getTCPv6Stats();
38
39 /**
40 * Get the UDP stats for IPv4 datagrams.
41 *
42 * @return a {@link UdpStats} object encapsulating the stats.
43 */
44 UdpStats getUDPv4Stats();
45
46 /**
47 * Get the UDP stats for IPv6 datagrams, if available. If not available separately, these may be 0 and included in
48 * IPv4 datagrams.
49 *
50 * @return a {@link UdpStats} object encapsulating the stats.
51 */
52 UdpStats getUDPv6Stats();
53
54 /**
55 * Gets a list of TCP and UDP connections.
56 *
57 * @return A list of {@link IPConnection} objects for TCP and UDP connections.
58 */
59 List<IPConnection> getConnections();
60
61 /**
62 * Encapsulates statistics associated with a TCP connection.
63 */
64 @Immutable
65 final class TcpStats {
66 private final long connectionsEstablished;
67 private final long connectionsActive;
68 private final long connectionsPassive;
69 private final long connectionFailures;
70 private final long connectionsReset;
71 private final long segmentsSent;
72 private final long segmentsReceived;
73 private final long segmentsRetransmitted;
74 private final long inErrors;
75 private final long outResets;
76
77 public TcpStats(long connectionsEstablished, long connectionsActive, long connectionsPassive,
78 long connectionFailures, long connectionsReset, long segmentsSent, long segmentsReceived,
79 long segmentsRetransmitted, long inErrors, long outResets) {
80 this.connectionsEstablished = connectionsEstablished;
81 this.connectionsActive = connectionsActive;
82 this.connectionsPassive = connectionsPassive;
83 this.connectionFailures = connectionFailures;
84 this.connectionsReset = connectionsReset;
85 this.segmentsSent = segmentsSent;
86 this.segmentsReceived = segmentsReceived;
87 this.segmentsRetransmitted = segmentsRetransmitted;
88 this.inErrors = inErrors;
89 this.outResets = outResets;
90 }
91
92 /**
93 * Connections Established is the number of TCP connections for which the current state is either ESTABLISHED or
94 * CLOSE-WAIT
95 *
96 * @return the connectionsEstablished
97 */
98 public long getConnectionsEstablished() {
99 return connectionsEstablished;
100 }
101
102 /**
103 * Connections Active is the number of times TCP connections have made a direct transition to the SYN-SENT state
104 * from the CLOSED state. In other words, it shows a number of connections which are initiated by the local
105 * computer. The value is a cumulative total.
106 *
107 * @return the connectionsActive
108 */
109 public long getConnectionsActive() {
110 return connectionsActive;
111 }
112
113 /**
114 * Connections Passive is the number of times TCP connections have made a direct transition to the SYN-RCVD
115 * state from the LISTEN state. In other words, it shows a number of connections to the local computer, which
116 * are initiated by remote computers. The value is a cumulative total.
117 *
118 * @return the connectionsPassive
119 */
120 public long getConnectionsPassive() {
121 return connectionsPassive;
122 }
123
124 /**
125 * Connection Failures is the number of times TCP connections have made a direct transition to the CLOSED state
126 * from the SYN-SENT state or the SYN-RCVD state, plus the number of times TCP connections have made a direct
127 * transition to the LISTEN state from the SYN-RCVD state.
128 *
129 * @return the connectionFailures
130 */
131 public long getConnectionFailures() {
132 return connectionFailures;
133 }
134
135 /**
136 * Connections Reset is the number of times TCP connections have made a direct transition to the CLOSED state
137 * from either the ESTABLISHED state or the CLOSE-WAIT state.
138 *
139 * @return the connectionsReset
140 */
141 public long getConnectionsReset() {
142 return connectionsReset;
143 }
144
145 /**
146 * Segments Sent is the number of segments sent, including those on current connections, but excluding those
147 * containing only retransmitted bytes.
148 *
149 * @return the segmentsSent
150 */
151 public long getSegmentsSent() {
152 return segmentsSent;
153 }
154
155 /**
156 * Segments Received is the number of segments received, including those received in error. This count includes
157 * segments received on currently established connections.
158 *
159 * @return the segmentsReceived
160 */
161 public long getSegmentsReceived() {
162 return segmentsReceived;
163 }
164
165 /**
166 * Segments Retransmitted is the number of segments retransmitted, that is, segments transmitted containing one
167 * or more previously transmitted bytes.
168 *
169 * @return the segmentsRetransmitted
170 */
171 public long getSegmentsRetransmitted() {
172 return segmentsRetransmitted;
173 }
174
175 /**
176 * The number of errors received.
177 *
178 * @return the inErrors
179 */
180 public long getInErrors() {
181 return inErrors;
182 }
183
184 /**
185 * The number of segments transmitted with the reset flag set.
186 *
187 * @return the outResets
188 */
189 public long getOutResets() {
190 return outResets;
191 }
192
193 @Override
194 public String toString() {
195 return "TcpStats [connectionsEstablished=" + connectionsEstablished + ", connectionsActive="
196 + connectionsActive + ", connectionsPassive=" + connectionsPassive + ", connectionFailures="
197 + connectionFailures + ", connectionsReset=" + connectionsReset + ", segmentsSent=" + segmentsSent
198 + ", segmentsReceived=" + segmentsReceived + ", segmentsRetransmitted=" + segmentsRetransmitted
199 + ", inErrors=" + inErrors + ", outResets=" + outResets + "]";
200 }
201 }
202
203 /**
204 * Encapsulates statistics associated with a UDP connection.
205 */
206 @Immutable
207 final class UdpStats {
208 private final long datagramsSent;
209 private final long datagramsReceived;
210 private final long datagramsNoPort;
211 private final long datagramsReceivedErrors;
212
213 public UdpStats(long datagramsSent, long datagramsReceived, long datagramsNoPort,
214 long datagramsReceivedErrors) {
215 this.datagramsSent = datagramsSent;
216 this.datagramsReceived = datagramsReceived;
217 this.datagramsNoPort = datagramsNoPort;
218 this.datagramsReceivedErrors = datagramsReceivedErrors;
219 }
220
221 /**
222 * Datagrams Sent is the number of UDP datagrams sent from the entity.
223 *
224 * @return the datagramsSent
225 */
226 public long getDatagramsSent() {
227 return datagramsSent;
228 }
229
230 /**
231 * Datagrams Received is the number of UDP datagrams delivered to UDP users.
232 *
233 * @return the datagramsReceived
234 */
235 public long getDatagramsReceived() {
236 return datagramsReceived;
237 }
238
239 /**
240 * Datagrams No Port is the number of received UDP datagrams for which there was no application at the
241 * destination port.
242 *
243 * @return the datagramsNoPort
244 */
245 public long getDatagramsNoPort() {
246 return datagramsNoPort;
247 }
248
249 /**
250 * Datagrams Received Errors is the number of received UDP datagrams that could not be delivered for reasons
251 * other than the lack of an application at the destination port.
252 *
253 * @return the datagramsReceivedErrors
254 */
255 public long getDatagramsReceivedErrors() {
256 return datagramsReceivedErrors;
257 }
258
259 @Override
260 public String toString() {
261 return "UdpStats [datagramsSent=" + datagramsSent + ", datagramsReceived=" + datagramsReceived
262 + ", datagramsNoPort=" + datagramsNoPort + ", datagramsReceivedErrors=" + datagramsReceivedErrors
263 + "]";
264 }
265 }
266
267 /**
268 * The TCP connection state as described in RFC 793.
269 */
270 enum TcpState {
271 UNKNOWN, CLOSED, LISTEN, SYN_SENT, SYN_RECV, ESTABLISHED, FIN_WAIT_1, FIN_WAIT_2, CLOSE_WAIT, CLOSING, LAST_ACK,
272 TIME_WAIT, NONE;
273 }
274
275 /**
276 * Encapsulates information associated with an IP connection.
277 */
278 @Immutable
279 final class IPConnection {
280 private final String type;
281 private final byte[] localAddress;
282 private final int localPort;
283 private final byte[] foreignAddress;
284 private final int foreignPort;
285 private final TcpState state;
286 private final int transmitQueue;
287 private final int receiveQueue;
288 private int owningProcessId;
289
290 public IPConnection(String type, byte[] localAddress, int localPort, byte[] foreignAddress, int foreignPort,
291 TcpState state, int transmitQueue, int receiveQueue, int owningProcessId) {
292 this.type = type;
293 this.localAddress = Arrays.copyOf(localAddress, localAddress.length);
294 this.localPort = localPort;
295 this.foreignAddress = Arrays.copyOf(foreignAddress, foreignAddress.length);
296 this.foreignPort = foreignPort;
297 this.state = state;
298 this.transmitQueue = transmitQueue;
299 this.receiveQueue = receiveQueue;
300 this.owningProcessId = owningProcessId;
301 }
302
303 /**
304 * Returns the connection protocol type, e.g., tcp4, tcp6, tcp46, udp4, udp6, udp46
305 *
306 * @return The protocol type
307 */
308 public String getType() {
309 return type;
310 }
311
312 /**
313 * Gets the local address. For IPv4 addresses this is a 4-byte array. For IPv6 addresses this is a 16-byte
314 * array.
315 * <p>
316 * On Unix operating systems, the 16-bit value may be truncated, giving only the high order bytes. IPv6
317 * addresses ending in zeroes should be considered suspect.
318 *
319 * @return The local address, or an empty array if the listener can accept a connection on any interface.
320 */
321 public byte[] getLocalAddress() {
322 return Arrays.copyOf(localAddress, localAddress.length);
323 }
324
325 /**
326 * Gets the local port.
327 *
328 * @return The local port, or 0 if unknown, or any port.
329 */
330 public int getLocalPort() {
331 return localPort;
332 }
333
334 /**
335 * Gets the foreign/remote address. For IPv4 addresses this is a 4-byte array. For IPv6 addresses this is a
336 * 16-byte array.
337 * <p>
338 * On Unix operating systems, this value may be truncated. IPv6 addresses ending in zeroes should be considered
339 * suspect.
340 *
341 * @return The foreign/remote address, or an empty array if unknown. An empty array will also result if
342 */
343 public byte[] getForeignAddress() {
344 return Arrays.copyOf(foreignAddress, foreignAddress.length);
345 }
346
347 /**
348 * Gets the foreign/remote port.
349 *
350 * @return The foreign/remote port, or 0 if unknown.
351 */
352 public int getForeignPort() {
353 return foreignPort;
354 }
355
356 /**
357 * Gets the connection state (TCP connections only).
358 *
359 * @return The connection state if known or relevant, null otherwise.
360 */
361 public TcpState getState() {
362 return state;
363 }
364
365 /**
366 * Gets the size of the transmit queue. Not available on Windows.
367 *
368 * @return The size of the transmit queue, or 0 if unknown.
369 */
370 public int getTransmitQueue() {
371 return transmitQueue;
372 }
373
374 /**
375 * Gets the size of the receive queue. Not available on Windows.
376 *
377 * @return The size of the receive queue, or 0 if unknown.
378 */
379 public int getReceiveQueue() {
380 return receiveQueue;
381 }
382
383 /**
384 * Gets the id of the process which holds this connection.
385 *
386 * @return The process id of the process which holds this connection if known, -1 otherwise.
387 */
388 public int getowningProcessId() {
389 return owningProcessId;
390 }
391
392 @Override
393 public String toString() {
394 String localIp = "*";
395 try {
396 localIp = InetAddress.getByAddress(localAddress).toString();
397 } catch (UnknownHostException e) { // NOSONAR squid:S108
398 }
399 String foreignIp = "*";
400 try {
401 foreignIp = InetAddress.getByAddress(foreignAddress).toString();
402 } catch (UnknownHostException e) { // NOSONAR squid:S108
403 }
404 return "IPConnection [type=" + type + ", localAddress=" + localIp + ", localPort=" + localPort
405 + ", foreignAddress=" + foreignIp + ", foreignPort=" + foreignPort + ", state=" + state
406 + ", transmitQueue=" + transmitQueue + ", receiveQueue=" + receiveQueue + ", owningProcessId="
407 + owningProcessId + "]";
408 }
409 }
410 }