-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add GetIfEntry, GetNetworkParams, and supporting IPHlpAPI structures #983
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,280 @@ | ||
/* Copyright (c) 2018 Daniel Widdis, All Rights Reserved | ||
* | ||
* The contents of this file is dual-licensed under 2 | ||
* alternative Open Source/Free licenses: LGPL 2.1 or later and | ||
* Apache License 2.0. (starting with JNA version 4.0.0). | ||
* | ||
* You can freely decide which license you want to apply to | ||
* the project. | ||
* | ||
* You may obtain a copy of the LGPL License at: | ||
* | ||
* http://www.gnu.org/licenses/licenses.html | ||
* | ||
* A copy is also included in the downloadable source code package | ||
* containing JNA, in file "LGPL2.1". | ||
* | ||
* You may obtain a copy of the Apache License at: | ||
* | ||
* http://www.apache.org/licenses/ | ||
* | ||
* A copy is also included in the downloadable source code package | ||
* containing JNA, in file "AL2.0". | ||
*/ | ||
package com.sun.jna.platform.win32; | ||
|
||
import com.sun.jna.Library; | ||
import com.sun.jna.Native; | ||
import com.sun.jna.Pointer; | ||
import com.sun.jna.Structure; | ||
import com.sun.jna.Structure.FieldOrder; | ||
import com.sun.jna.platform.win32.Guid.GUID; | ||
import com.sun.jna.platform.win32.WinDef.UCHAR; | ||
import com.sun.jna.platform.win32.WinDef.UINT; | ||
import com.sun.jna.platform.win32.WinDef.ULONG; | ||
import com.sun.jna.platform.win32.WinDef.ULONGByReference; | ||
import com.sun.jna.win32.W32APIOptions; | ||
|
||
/** | ||
* Windows IP Helper API | ||
* | ||
* @see <A HREF= | ||
* "https://msdn.microsoft.com/en-us/library/windows/desktop/aa373083(v=vs.85).aspx">IP | ||
* Helper Reference</A> | ||
*/ | ||
public interface IPHlpAPI extends Library { | ||
IPHlpAPI INSTANCE = Native.load("IPHlpAPI", IPHlpAPI.class, W32APIOptions.DEFAULT_OPTIONS); | ||
|
||
int IF_MAX_STRING_SIZE = 256; | ||
int IF_MAX_PHYS_ADDRESS_LENGTH = 32; | ||
int MAX_INTERFACE_NAME_LEN = 256; | ||
int MAXLEN_IFDESCR = 256; | ||
int MAXLEN_PHYSADDR = 8; | ||
int MAX_HOSTNAME_LEN = 128; | ||
int MAX_DOMAIN_NAME_LEN = 128; | ||
int MAX_SCOPE_ID_LEN = 256; | ||
|
||
/** | ||
* The MIB_IFROW structure stores information about a particular interface. | ||
* | ||
* @see <A HREF= | ||
* "https://docs.microsoft.com/en-us/previous-versions/windows/desktop/api/ifmib/ns-ifmib-_mib_ifrow">MIB_IFROW</A> | ||
*/ | ||
@FieldOrder({ "wszName", "dwIndex", "dwType", "dwMtu", "dwSpeed", "dwPhysAddrLen", "bPhysAddr", "dwAdminStatus", | ||
"dwOperStatus", "dwLastChange", "dwInOctets", "dwInUcastPkts", "dwInNUcastPkts", "dwInDiscards", | ||
"dwInErrors", "dwInUnknownProtos", "dwOutOctets", "dwOutUcastPkts", "dwOutNUcastPkts", "dwOutDiscards", | ||
"dwOutErrors", "dwOutQLen", "dwDescrLen", "bDescr" }) | ||
class MIB_IFROW extends Structure { | ||
public char[] wszName = new char[MAX_INTERFACE_NAME_LEN]; | ||
public int dwIndex; | ||
public int dwType; | ||
public int dwMtu; | ||
public int dwSpeed; | ||
public int dwPhysAddrLen; | ||
public byte[] bPhysAddr = new byte[MAXLEN_PHYSADDR]; | ||
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[MAXLEN_IFDESCR]; | ||
} | ||
|
||
/** | ||
* The MIB_IF_ROW2 structure stores information about a particular | ||
* interface. | ||
* | ||
* @see <A HREF= | ||
* "https://msdn.microsoft.com/library/windows/hardware/ff559214">MIB_IF_ROW2</A> | ||
*/ | ||
@FieldOrder({ "InterfaceLuid", "InterfaceIndex", "InterfaceGuid", "Alias", "Description", "PhysicalAddressLength", | ||
"PhysicalAddress", "PermanentPhysicalAddress", "Mtu", "Type", "TunnelType", "MediaType", | ||
"PhysicalMediumType", "AccessType", "DirectionType", "InterfaceAndOperStatusFlags", "OperStatus", | ||
"AdminStatus", "MediaConnectState", "NetworkGuid", "ConnectionType", "TransmitLinkSpeed", | ||
"ReceiveLinkSpeed", "InOctets", "InUcastPkts", "InNUcastPkts", "InDiscards", "InErrors", "InUnknownProtos", | ||
"InUcastOctets", "InMulticastOctets", "InBroadcastOctets", "OutOctets", "OutUcastPkts", "OutNUcastPkts", | ||
"OutDiscards", "OutErrors", "OutUcastOctets", "OutMulticastOctets", "OutBroadcastOctets", "OutQLen" }) | ||
class MIB_IF_ROW2 extends Structure { | ||
public long InterfaceLuid; // 64-bit union | ||
public ULONG InterfaceIndex; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Would int be an alternative? (applies to other definitions as well). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Also applies to some of my other PRs. As a structure mapping it would work, however, I have tried (not always consistently) to use the mapped type when variables are unsigned. I've gone back and forth a few times on many of these... using int, we require the user to know to interpret the unsigned value, while ULONG or DWORD offer There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Your argument is sound - the question was really meant as a question, so if you think it would be better to bind it as a wrapped value, I'm ok with it too. The benefit I see in the int is, that it is the "natural" integral number type in java and thus easier to deal with. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's ok to leave it as int here, because the javadoc makes it clear what the underlying value is and there's likely a tiny performance improvement to avoiding the extra object creation. As I said I went back and forth on this (I literally did search-and-replace, and then undo, at least twice) before submitting. I might suggest a Global JNA util method that converts unsigned values, though, so users don't have to always reinvent the wheel. |
||
public GUID InterfaceGuid; | ||
public char[] Alias = new char[IF_MAX_STRING_SIZE + 1]; | ||
public char[] Description = new char[IF_MAX_STRING_SIZE + 1]; | ||
public ULONG PhysicalAddressLength; | ||
public UCHAR[] PhysicalAddress = new UCHAR[IF_MAX_PHYS_ADDRESS_LENGTH]; | ||
public UCHAR[] PermanentPhysicalAddress = new UCHAR[IF_MAX_PHYS_ADDRESS_LENGTH]; | ||
public ULONG Mtu; | ||
public ULONG Type; | ||
// enums | ||
public int TunnelType; | ||
public int MediaType; | ||
public int PhysicalMediumType; | ||
public int AccessType; | ||
public int DirectionType; | ||
// 8-bit structure | ||
public byte InterfaceAndOperStatusFlags; | ||
// enums | ||
public int OperStatus; | ||
public int AdminStatus; | ||
public int MediaConnectState; | ||
public GUID NetworkGuid; | ||
public int ConnectionType; | ||
public long TransmitLinkSpeed; | ||
public long ReceiveLinkSpeed; | ||
public long InOctets; | ||
public long InUcastPkts; | ||
public long InNUcastPkts; | ||
public long InDiscards; | ||
public long InErrors; | ||
public long InUnknownProtos; | ||
public long InUcastOctets; | ||
public long InMulticastOctets; | ||
public long InBroadcastOctets; | ||
public long OutOctets; | ||
public long OutUcastPkts; | ||
public long OutNUcastPkts; | ||
public long OutDiscards; | ||
public long OutErrors; | ||
public long OutUcastOctets; | ||
public long OutMulticastOctets; | ||
public long OutBroadcastOctets; | ||
public long OutQLen; | ||
} | ||
|
||
/** | ||
* The IP_ADDRESS_STRING structure stores an IPv4 address in dotted decimal | ||
* notation. The IP_ADDRESS_STRING structure definition is also the type | ||
* definition for the IP_MASK_STRING structure. | ||
* | ||
* @see <A HREF= | ||
* "https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-ip_address_string">IP_ADDRESS_STRING</A> | ||
*/ | ||
@FieldOrder({ "String" }) | ||
class IP_ADDRESS_STRING extends Structure { | ||
// Null terminated string | ||
// up to 3 chars (decimal 0-255) and dot | ||
// ending with null | ||
public byte[] String = new byte[16]; | ||
} | ||
|
||
/** | ||
* The IP_ADDR_STRING structure represents a node in a linked-list of IPv4 | ||
* addresses. | ||
* | ||
* @see <A HREF= | ||
* "https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-_ip_addr_string">IP_ADDR_STRING</A> | ||
*/ | ||
@FieldOrder({ "Next", "IpAddress", "IpMask", "Context" }) | ||
class IP_ADDR_STRING extends Structure { | ||
public ByReference Next; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please qualify this to |
||
public IP_ADDRESS_STRING IpAddress; | ||
public IP_ADDRESS_STRING IpMask; | ||
public int Context; | ||
|
||
public static class ByReference extends IP_ADDR_STRING implements Structure.ByReference { | ||
} | ||
} | ||
|
||
/** | ||
* The FIXED_INFO structure contains information that is the same across all | ||
* the interfaces on a computer. | ||
* | ||
* @see <A HREF= | ||
* "https://docs.microsoft.com/en-us/windows/desktop/api/iptypes/ns-iptypes-fixed_info_w2ksp1">FIXED_INFO</A> | ||
*/ | ||
@FieldOrder({ "HostName", "DomainName", "CurrentDnsServer", "DnsServerList", "NodeType", "ScopeId", "EnableRouting", | ||
"EnableProxy", "EnableDns" }) | ||
class FIXED_INFO extends Structure { | ||
public byte[] HostName = new byte[MAX_HOSTNAME_LEN + 4]; | ||
public byte[] DomainName = new byte[MAX_DOMAIN_NAME_LEN + 4]; | ||
public IP_ADDR_STRING.ByReference CurrentDnsServer; // IP_ADDR_STRING | ||
public IP_ADDR_STRING DnsServerList; | ||
public UINT NodeType; | ||
public byte[] ScopeId = new byte[MAX_SCOPE_ID_LEN + 4]; | ||
public UINT EnableRouting; | ||
public UINT EnableProxy; | ||
public UINT EnableDns; | ||
|
||
public FIXED_INFO(Pointer p) { | ||
super(p); | ||
read(); | ||
} | ||
|
||
public FIXED_INFO() { | ||
super(); | ||
} | ||
} | ||
|
||
/** | ||
* The GetIfEntry function retrieves information for the specified interface | ||
* on the local computer. | ||
* | ||
* The dwIndex member in the MIB_IFROW structure pointed to by the pIfRow | ||
* parameter must be initialized to a valid network interface index | ||
* retrieved by a previous call to the GetIfTable, GetIfTable2, or | ||
* GetIfTable2Ex function. The GetIfEntry function will fail if the dwIndex | ||
* member of the MIB_IFROW pointed to by the pIfRow parameter does not match | ||
* an existing interface index on the local computer. | ||
* | ||
* @param pIfRow | ||
* A pointer to a MIB_IFROW structure that, on successful return, | ||
* receives information for an interface on the local computer. | ||
* On input, set the dwIndex member of MIB_IFROW to the index of | ||
* the interface for which to retrieve information. | ||
* @return If the function succeeds, the return value is NO_ERROR. | ||
*/ | ||
int GetIfEntry(MIB_IFROW pIfRow); | ||
|
||
/** | ||
* The GetIfEntry2 function retrieves information for the specified | ||
* interface on the local computer. | ||
* | ||
* On input, at least one of the following members in the MIB_IF_ROW2 | ||
* structure passed in the Row parameter must be initialized: InterfaceLuid | ||
* or InterfaceIndex. The fields are used in the order listed above. So if | ||
* the InterfaceLuid is specified, then this member is used to determine the | ||
* interface. If no value was set for the InterfaceLuid member (the value of | ||
* this member was set to zero), then the InterfaceIndex member is next used | ||
* to determine the interface. On output, the remaining fields of the | ||
* MIB_IF_ROW2 structure pointed to by the Row parameter are filled in. | ||
* | ||
* @param pIfRow2 | ||
* A pointer to a MIB_IF_ROW2 structure that, on successful | ||
* return, receives information for an interface on the local | ||
* computer. On input, the InterfaceLuid or the InterfaceIndex | ||
* member of the MIB_IF_ROW2 must be set to the interface for | ||
* which to retrieve information. | ||
* @return If the function succeeds, the return value is NO_ERROR. | ||
*/ | ||
int GetIfEntry2(MIB_IF_ROW2 pIfRow2); | ||
|
||
/** | ||
* The GetNetworkParams function retrieves network parameters for the local | ||
* computer. | ||
* | ||
* @param pFixedInfo | ||
* A pointer to a buffer that contains a FIXED_INFO structure | ||
* that receives the network parameters for the local computer, | ||
* if the function was successful. This buffer must be allocated | ||
* by the caller prior to calling the GetNetworkParams function. | ||
* @param pOutBufLen | ||
* A pointer to a ULONG variable that specifies the size of the | ||
* FIXED_INFO structure. If this size is insufficient to hold the | ||
* information, GetNetworkParams fills in this variable with the | ||
* required size, and returns an error code of | ||
* ERROR_BUFFER_OVERFLOW. | ||
* @return If the function succeeds, the return value is ERROR_SUCCESS. | ||
*/ | ||
int GetNetworkParams(FIXED_INFO pFixedInfo, ULONGByReference pOutBufLen); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this safe to use the raw value here instead of the union?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's safe, as it's 64-bits. The alternative would be a multi-layer NET_LUID union in JNA with one alternative being a 64-bit Value (the intended return) and the actual information encoded in 5 of the 8 bytes. See https://msdn.microsoft.com/library/windows/hardware/ff568747 . Happy to try to add that NET_LUID structure if I can figure out how; but at this layer it's possible for it to be returned and then parsed by the user with shifting and bitmasks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I agree, retrieving the correct value can be implemented as a helper method on the structure, if needed.