Reputation: 73
I need to get the index of a Network Interface in Windows. There is NetworkInterface.getIndex() method to do this, but it's only available starting Java 7. The requirement from the Boss is that the app needs to run in Java 6.
After some searching, I found JNA lib to call Win API functions. The function itself is GetIfTable (http://msdn.microsoft.com/en-us/library/windows/desktop/aa365943(v=vs.85).aspx)
However, I've not been able to successfully call this function using JNA. The return value of GetIfTable is always 122 which means ERROR_INSUFFICIENT_BUFFER. Even if I keep adding buffer it still says insufficient buffer, until when the supplied value reach certain number, then "Invalid memory access" error shows up.
Here's what I already did:
public interface IpHlpAPI extends StdCallLibrary {
IpHlpAPI INSTANCE = (IpHlpAPI) Native.loadLibrary("IpHlpAPI", IpHlpAPI.class);
public static class MIB_IFTABLE extends Structure {
public int dwNumEntries;
public MIB_IFROW table[] = new IpHlpAPI.MIB_IFROW[1];
public MIB_IFTABLE() {}
public MIB_IFTABLE(int size) {
this.allocateMemory(size);
}
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"dwNumEntries", "table"});
}
}
public static class MIB_IFROW extends Structure {
public char wszName[] = new char[256];
public int dwIndex;
public int dwType;
public int dwMtu;
public int dwSpeed;
public int dwPhysAddrLen;
public byte bPhysAddr[] = new byte[8];
public int dwAdminStatus;
public int dwOperStatus;
public int dwLastChange;
public int dwInOctets;
public int dwInUcastPkts;
public int dwInNUcastPkts;
public int dwInDiscards;
public int dwInErrors;
public int dwInUnknownProtos;
public int dwOutOctets;
public int dwOutUcastPkts;
public int dwOutNUcastPkts;
public int dwOutDiscards;
public int dwOutErrors;
public int dwOutQLen;
public int dwDescrLen;
public byte bDescr[] = new byte[256];
@Override
protected List getFieldOrder() {
return Arrays.asList(new String[]{"wszName", "dwIndex", "dwType", "dwMtu",
"dwSpeed", "dwPhysAddrLen", "bPhysAddr", "dwAdminStatus", "dwOperStatus",
"dwLastChange", "dwInOctets", "dwInUcastPkts", "dwInNUcastPkts", "dwInDiscards",
"dwInErrors", "dwInUnknownProtos", "dwOutOctets", "dwOutUcastPkts",
"dwOutNUcastPkts", "dwOutDiscards", "dwOutErrors", "dwOutQLen", "dwDescrLen", "bDescr"});
}
}
int GetIfTable(MIB_IFTABLE pIfTable, IntByReference pdwSize, boolean bOrder);
}
public static void main(String[] args) {
IpHlpAPI ipHlpApi = IpHlpAPI.INSTANCE;
IpHlpAPI.MIB_IFTABLE ifTable = new IpHlpAPI.MIB_IFTABLE();
IntByReference psize = new IntByReference(ifTable.size());
int status = ipHlpApi.GetIfTable(ifTable, psize, false);
if (status == 122) {
// Calculate the required number of elements in the MIB_IFROW array
ifTable = new IpHlpAPI.MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
psize.setValue(ifTable.size());
status = ipHlpApi.GetIfTable(ifTable, psize, false);
System.out.println(status);
}
System.exit(0);
}
Any ideas why is this happening?
Upvotes: 1
Views: 485
Reputation: 10069
Your input structure isn't large enough. You need to reallocate the table
field to be sufficiently large based on the value returned in the pdwSize
parameter.
Add a constructor to MIB_IFTABLE
that indicates the size of the table
array and initializes it accordingly. That will automatically give you a bigger buffer.
MIB_IFTABLE ifTable = new MIB_IFTABLE();
IntByReference psize = new IntByReference(ifTable.size());
int status = ipHlpApi.GetIfTable(ifTable, psize, false);
if (status == 122) {
// Calculate the required number of elements in the MIB_IFROW array
ifTable = new MIB_IFTABLE((psize.getValue() - 4) / ifTable.table[0].size());
psize.setValue(ifTable.size());
status = ipHlpApi.GetIfTable(ifTable, psize, false);
// If status is still 122, then there's an issue with the MIB_IFROW definition
// ...
}
EDIT
Change your constructor:
public MIB_IFTABLE(int nentries) {
this.dwNumEntries = nentries;
this.table = (MIB_IFROW[])new MIB_IFROW().toArray(nentries);
}
You should probably initialize your other ctor to have a default value for dwNumEntries
; as it is you'll be passing in a default value of zero, which will guarantee you get a return value of 122 on the first call. I'm assuming dwNumEntries
refers to the size of the array.
Upvotes: 1