How does one map the function below to java with jnr-ffi?
BOOLEAN PacketRequest(LPADAPTER AdapterObject,BOOLEAN Set,PPACKET_OID_DATA OidData);
Example (C): https://github.com/patmarion/winpcap/blob/master/WpcapSrc_4_1_3/Examples/PacketDriver/GetMacAddress/GetMacAddress.c
public interface NativeMappings {
public static class PPACKET_OID_DATA extends Struct {
public final UnsignedLong Oid = new UnsignedLong();
public final UnsignedLong Length = new UnsignedLong();
public final byte[] Data = new byte[6];
public PPACKET_OID_DATA(Runtime runtime) {
super(runtime);
}
}
Pointer PacketOpenAdapter(String AdapterName);
int PacketRequest(Pointer AdapterObject, int set, @Out PPACKET_OID_DATA OidData);
void PacketCloseAdapter(Pointer lpAdapter);
public static class Main {
public static void main(String[] args) {
NativeMappings mappings = LibraryLoader.create(NativeMappings.class).load("Packet");
Runtime runtime = Runtime.getRuntime(mappings);
Pointer adapterObject = mappings.PacketOpenAdapter("\\Device\\NPF_{53152A2F-39F7-458E-BD58-24D17099256A}");
PPACKET_OID_DATA oid_data = new PPACKET_OID_DATA(runtime);
oid_data.Oid.set(0x01010102L);
oid_data.Length.set(6L);
int status = mappings.PacketRequest(adapterObject, 0, oid_data);
if (status == 0) {
System.out.println("Fail.");
} else {
System.out.println("Success.");
}
mappings.PacketCloseAdapter(adapterObject);
}
}
}
First of all to make a propper mapping you should look at the definitions of types you are mapping.
PacketRequestfunction returnsBOOLEANvariable. According to windows data type description,BOOLEANis declared astypedef BYTE BOOLEAN;. That means, that you can usebytetype as function type in java. But JNR also supports mappingbooleantype to/from nativebyte. So both definitions are correct:byte PacketRequest (...)boolean PacketRequest (...)Next, you need to map parameters. Same here, look at the definitions and you'll know what types to use. The result would be:
The
setparameter was incorrectly declared asint. Moreover the@Outannotation of the last field tells JNR to pass an empty structure without copying values to native memory. So no pre-set values will be passed.The last parameter has
PPACKET_OID_DATAtype - a structure.Structure mapping is a bit more complex than for native types. You can't use java types here. Instead you should use
jnr.ffi.Structinner classes to define struct fields. This rule includes array definitions. The correct definition for your structure will look like this:Notice this
UCHARarray definition. Natively this type is defined asunsigned char, so for JNR structure it would map tojnr.ffi.Strunc.Unsigned8class orjnr.ffi.Struct.BYTE(which is pretty much the same).To declare an array field you should initialize array in construction time. You need to use
jnr.ffi.Struct#array(...)functions to do that properly. That aslo means that you should know the size of the array. The example is shown above.Why we should define it this way? During initialization,
Structis some kind of a pointer of variable length. Each inner-class field, initialized in it reserves its own space increases maximun size of this pointer. So each field is a "view" to some memory fragment with its own way of interacting with this memory (public methods). But to make an array of such views you need to fill the empty array with view instances. That is just whatarrayfunction does.