View Javadoc
1   /*
2    * Copyright 2020-2022 The OSHI Project Contributors
3    * SPDX-License-Identifier: MIT
4    */
5   package oshi.driver.mac.net;
6   
7   import java.util.HashMap;
8   import java.util.Map;
9   
10  import org.slf4j.Logger;
11  import org.slf4j.LoggerFactory;
12  
13  import com.sun.jna.Memory;
14  import com.sun.jna.Pointer;
15  import com.sun.jna.platform.mac.SystemB;
16  import com.sun.jna.platform.mac.SystemB.IFmsgHdr;
17  import com.sun.jna.platform.mac.SystemB.IFmsgHdr2;
18  import com.sun.jna.platform.unix.LibCAPI.size_t;
19  
20  import oshi.annotation.concurrent.Immutable;
21  import oshi.annotation.concurrent.ThreadSafe;
22  import oshi.jna.ByRef.CloseableSizeTByReference;
23  
24  /**
25   * Utility to query NetStat.
26   */
27  @ThreadSafe
28  public final class NetStat {
29  
30      private static final Logger LOG = LoggerFactory.getLogger(NetStat.class);
31  
32      private static final int CTL_NET = 4;
33      private static final int PF_ROUTE = 17;
34      private static final int NET_RT_IFLIST2 = 6;
35      private static final int RTM_IFINFO2 = 0x12;
36  
37      private NetStat() {
38      }
39  
40      /**
41       * Map data for network interfaces.
42       *
43       * @param index If positive, limit the map to only return data for this interface index. If negative, returns data
44       *              for all indices.
45       *
46       * @return a map of {@link IFdata} object indexed by the interface index, encapsulating the stats
47       */
48      public static Map<Integer, IFdata> queryIFdata(int index) {
49          // Ported from source code of "netstat -ir". See
50          // https://opensource.apple.com/source/network_cmds/network_cmds-457/netstat.tproj/if.c
51          Map<Integer, IFdata> data = new HashMap<>();
52          // Get buffer of all interface information
53          int[] mib = { CTL_NET, PF_ROUTE, 0, 0, NET_RT_IFLIST2, 0 };
54          try (CloseableSizeTByReference len = new CloseableSizeTByReference()) {
55              if (0 != SystemB.INSTANCE.sysctl(mib, 6, null, len, null, size_t.ZERO)) {
56                  LOG.error("Didn't get buffer length for IFLIST2");
57                  return data;
58              }
59              try (Memory buf = new Memory(len.longValue())) {
60                  if (0 != SystemB.INSTANCE.sysctl(mib, 6, buf, len, null, size_t.ZERO)) {
61                      LOG.error("Didn't get buffer for IFLIST2");
62                      return data;
63                  }
64                  final long now = System.currentTimeMillis();
65  
66                  // Iterate offset from buf's pointer up to limit of buf
67                  int lim = (int) (buf.size() - new IFmsgHdr().size());
68                  int offset = 0;
69                  while (offset < lim) {
70                      // Get pointer to current native part of buf
71                      Pointer p = buf.share(offset);
72                      // Cast pointer to if_msghdr
73                      IFmsgHdr ifm = new IFmsgHdr(p);
74                      ifm.read();
75                      // Advance next
76                      offset += ifm.ifm_msglen;
77                      // Skip messages which are not the right format
78                      if (ifm.ifm_type == RTM_IFINFO2) {
79                          // Cast pointer to if_msghdr2
80                          IFmsgHdr2 if2m = new IFmsgHdr2(p);
81                          if2m.read();
82                          if (index < 0 || index == if2m.ifm_index) {
83                              data.put((int) if2m.ifm_index,
84                                      new IFdata(0xff & if2m.ifm_data.ifi_type, if2m.ifm_data.ifi_opackets,
85                                              if2m.ifm_data.ifi_ipackets, if2m.ifm_data.ifi_obytes,
86                                              if2m.ifm_data.ifi_ibytes, if2m.ifm_data.ifi_oerrors,
87                                              if2m.ifm_data.ifi_ierrors, if2m.ifm_data.ifi_collisions,
88                                              if2m.ifm_data.ifi_iqdrops, if2m.ifm_data.ifi_baudrate, now));
89                              if (index >= 0) {
90                                  return data;
91                              }
92                          }
93                      }
94                  }
95              }
96          }
97          return data;
98      }
99  
100     /**
101      * Class to encapsulate IF data for method return
102      */
103     @Immutable
104     public static class IFdata {
105         private final int ifType;
106         private final long oPackets;
107         private final long iPackets;
108         private final long oBytes;
109         private final long iBytes;
110         private final long oErrors;
111         private final long iErrors;
112         private final long collisions;
113         private final long iDrops;
114         private final long speed;
115         private final long timeStamp;
116 
117         IFdata(int ifType, // NOSONAR squid:S00107
118                 long oPackets, long iPackets, long oBytes, long iBytes, long oErrors, long iErrors, long collisions,
119                 long iDrops, long speed, long timeStamp) {
120             this.ifType = ifType;
121             this.oPackets = oPackets & 0xffffffffL;
122             this.iPackets = iPackets & 0xffffffffL;
123             this.oBytes = oBytes & 0xffffffffL;
124             this.iBytes = iBytes & 0xffffffffL;
125             this.oErrors = oErrors & 0xffffffffL;
126             this.iErrors = iErrors & 0xffffffffL;
127             this.collisions = collisions & 0xffffffffL;
128             this.iDrops = iDrops & 0xffffffffL;
129             this.speed = speed & 0xffffffffL;
130             this.timeStamp = timeStamp;
131         }
132 
133         /**
134          * @return the ifType
135          */
136         public int getIfType() {
137             return ifType;
138         }
139 
140         /**
141          * @return the oPackets
142          */
143         public long getOPackets() {
144             return oPackets;
145         }
146 
147         /**
148          * @return the iPackets
149          */
150         public long getIPackets() {
151             return iPackets;
152         }
153 
154         /**
155          * @return the oBytes
156          */
157         public long getOBytes() {
158             return oBytes;
159         }
160 
161         /**
162          * @return the iBytes
163          */
164         public long getIBytes() {
165             return iBytes;
166         }
167 
168         /**
169          * @return the oErrors
170          */
171         public long getOErrors() {
172             return oErrors;
173         }
174 
175         /**
176          * @return the iErrors
177          */
178         public long getIErrors() {
179             return iErrors;
180         }
181 
182         /**
183          * @return the collisions
184          */
185         public long getCollisions() {
186             return collisions;
187         }
188 
189         /**
190          * @return the iDrops
191          */
192         public long getIDrops() {
193             return iDrops;
194         }
195 
196         /**
197          * @return the speed
198          */
199         public long getSpeed() {
200             return speed;
201         }
202 
203         /**
204          * @return the timeStamp
205          */
206         public long getTimeStamp() {
207             return timeStamp;
208         }
209     }
210 }