My question is about the Win32-Ada bindings provided by the packages:
I would like to use the following function defined in the package Win32.Mgmtapi:
function SnmpMgrOidToStr
(oid : access Win32.Snmp.AsnObjectIdentifier;
string : access Win32.LPSTR)
return Win32.BOOL;
I have access to a variable Variable_Binding of the type Win32.Snmp.a_RFC1157VarBind_t. The following four types are defined in the package Win32.Snmp:
type AsnObjectIdentifier is record
idLength : Win32.UINT;
ids : Win32.PUINT;
end record;
subtype AsnObjectName is AsnObjectIdentifier;
type RFC1157VarBind is record
name : AsnObjectName;
value : AsnObjectSyntax;
end record;
type a_RFC1157VarBind_t is access all RFC1157VarBind;
Shortened example code:
with Win32;
with Win32.Mgmtapi;
with Win32.Snmp;
procedure Test is
begin
-- [...]
declare
Variable_Binding : aliased Win32.Snmp.a_RFC1157VarBind_t := (...);
OID_String : access Win32.LPSTR;
Return_Value : Win32.BOOL;
begin
Return_Value := Win32.Mgmtapi.SnmpMgrOidToStr
(oid => Variable_Binding.name, -- type is not compatible
string => OID_String);
end;
end Test;
My three questions:
- The function
SnmpMgrOidToStrrequires an access type for the parametername. The componentnamedefined in the typeRFC1157VarBindis not compatible to this access type. What are my options to convert the componentnameof the variableVariable_Bindingto an access type? - I assume that the function
SnmpMgrOidToStrallocates the required memory for the variableOID_Stringof the typeWin32.LPSTR. How can I convert the typeWin32.LPSTRto an Ada string (String/Unbounded_String)? - How can I free the allocated memory after a converstion to an Ada string?
Update:
I added a full SNMP example. This requires an enabled and configured Windows SNMP service. The program output should be:
Opened session.
Converted string to object identifier.
Copied object identifier.
Sent request.
Type is: 4
WORKSTATION
system.sysName.0
Closed session.
The documentation of the function SnmpMgrRequest states:
Note The SnmpVarBind array pointed to by the SnmpVarBindList structure must be allocated using the SnmpUtilMemAlloc function.
And according to the documentation of the function SnmpUtilMemAlloc the function SnmpUtilMemFree should be used to free the allocated memory.
I think that I am allocating the memory correctly using ths procedure call:
-- Allocate memory
-- Allocated memory is not freed properly
SnmpUtilMemAlloc (Win32.UINT (Win32.Snmp.RFC1157VarBind'Size * System.Storage_Unit));
New questions:
- Is this procedure call correct?
- How can I use the function
SnmpUtilMemFreeto free the allocated memory?
At the moment the memory is not freed properly according to the tool Dr. Memory (Version 2.2.0-1):
Error #1: LEAK 1536 direct bytes 0x0418b850-0x0418be50 + 0 indirect bytes
# 0 replace_RtlAllocateHeap [d:\drmemory_package\common\alloc_replace.c:3771]
# 1 KERNELBASE.dll!GlobalAlloc +0x6d (0x75404015 <KERNELBASE.dll+0x14015>)
# 2 snmpapi.dll!SnmpUtilMemAlloc +0xf (0x73db1ee8 <snmpapi.dll+0x1ee8>)
# 3 _ada_snmp_example [C:/Users/username/Desktop/SNMPExample/src/snmp_example.adb:123]
# 4 main [C:\Users\username\Desktop\SNMPExample\obj/b__snmp_example.adb:259]
Full source code:
with Ada.Text_IO;
with Ada.Unchecked_Conversion;
with Interfaces.C.Strings;
with System;
with Win32;
with Win32.Mgmtapi;
with Win32.Snmp;
procedure SNMP_Example
is
-- Imported functions and procedures
procedure SnmpUtilMemAlloc (nBytes : Win32.UINT);
pragma Import (Stdcall, SnmpUtilMemAlloc, "SnmpUtilMemAlloc");
procedure SnmpUtilMemFree (pMem : Win32.LPVOID);
pragma Import (Stdcall, SnmpUtilMemFree, "SnmpUtilMemFree");
function SnmpUtilOidCpy
(DestObjId : access Win32.Snmp.AsnObjectIdentifier;
SrcObjId : access Win32.Snmp.AsnObjectIdentifier)
return Win32.INT;
pragma Import (Stdcall, SnmpUtilOidCpy, "SnmpUtilOidCpy");
procedure SnmpUtilOidFree (Obj : access Win32.Snmp.AsnObjectIdentifier);
pragma Import (Stdcall, SnmpUtilOidFree, "SnmpUtilOidFree");
procedure SnmpUtilVarBindFree (VarBind : access Win32.Snmp.RFC1157VarBind);
pragma Import (Stdcall, SnmpUtilVarBindFree, "SnmpUtilVarBindFree");
procedure SnmpUtilVarBindListFree (VarBindList : access Win32.Snmp.RFC1157VarBindList);
pragma Import (Stdcall, SnmpUtilVarBindListFree, "SnmpUtilVarBindListFree");
-- Conversion related
function To_LPVOID is new Ada.Unchecked_Conversion (Win32.LPSTR, Win32.LPVOID);
function To_PCSTR is new Ada.Unchecked_Conversion (Win32.PBYTE, Win32.PCSTR);
-- Linker options
pragma Linker_Options ("-lmgmtapi");
pragma Linker_Options ("-lsnmpapi");
-- Connection related (Ada)
IP_Address : constant String := "127.0.0.1";
Community_String : constant String := "public";
Timeout_MS : constant Integer := 500;
Number_Of_Retries : constant Integer := 1;
-- Connection related (C)
IP_Address_C : Interfaces.C.Strings.chars_ptr := Interfaces.C.Strings.New_String (IP_Address);
Community_String_C : Interfaces.C.Strings.chars_ptr := Interfaces.C.Strings.New_String (Community_String);
-- Connection related (Win32)
IP_Address_Win32 : constant Win32.LPSTR := Win32.To_PSTR (IP_Address_C);
Community_String_Win32 : constant Win32.LPSTR := Win32.To_PSTR (Community_String_C);
Timeout_MS_Win32 : constant Win32.INT := Win32.INT (Timeout_MS);
Number_Of_Retries_Win32 : constant Win32.INT := Win32.INT (Number_Of_Retries);
-- Comparison of types related
use type Interfaces.C.int;
use type Win32.BOOL;
use type Win32.Mgmtapi.LPSNMP_MGR_SESSION;
-- Session
SNMP_Session : Win32.Mgmtapi.LPSNMP_MGR_SESSION;
-- Custom types
type Counter_Type is mod 2**32 - 1;
type Gauge_Type is mod 2**32 - 1;
begin
-- Open session
SNMP_Session := Win32.Mgmtapi.SnmpMgrOpen
(lpAgentAddress => IP_Address_Win32,
lpAgentCommunity => Community_String_Win32,
nTimeOut => Timeout_MS_Win32,
nRetries => Number_Of_Retries_Win32);
if SNMP_Session = null then
Ada.Text_IO.Put_Line ("Failed to open session.");
else
Ada.Text_IO.Put_Line ("Opened session.");
Send_Request : declare
-- Request related (Ada)
SNMP_Object_Identifier_Ada : constant String := ".1.3.6.1.2.1.1.5.0";
-- Request related (C)
SNMP_Object_Identifier_C : Interfaces.C.Strings.chars_ptr := Interfaces.C.Strings.New_String (SNMP_Object_Identifier_Ada);
-- Request related (Win32)
SNMP_Object_Identifier_Win32 : constant Win32.LPSTR := Win32.To_PSTR (SNMP_Object_Identifier_C);
SNMP_Object_Identifier : aliased Win32.Snmp.AsnObjectIdentifier;
Variable_Bindings : aliased Win32.Snmp.RFC1157VarBindList;
Variable_Bindings_Entry : aliased Win32.Snmp.RFC1157VarBind;
Error_Status : aliased Win32.Snmp.AsnInteger;
Error_Index : aliased Win32.Snmp.AsnInteger;
Return_Value_String_To_OID_Conversion : Win32.BOOL;
Return_Value_OID_Copy : Win32.INT;
Return_Value_Request : Win32.INT;
Return_Value_OID_To_String_Conversion : Win32.BOOL;
begin
Return_Value_String_To_OID_Conversion := Win32.Mgmtapi.SnmpMgrStrToOid
(string => SNMP_Object_Identifier_Win32,
oid => SNMP_Object_Identifier'Access);
if Return_Value_String_To_OID_Conversion = 0 then
Ada.Text_IO.Put_Line ("Failed to convert string to object identifier.");
else
Ada.Text_IO.Put_Line ("Converted string to object identifier.");
-- Allocate memory
-- Allocated memory is not freed properly
SnmpUtilMemAlloc (Win32.UINT (Win32.Snmp.RFC1157VarBind'Size * System.Storage_Unit));
Return_Value_OID_Copy := SnmpUtilOidCpy
(DestObjId => Variable_Bindings_Entry.name'Unrestricted_Access,
SrcObjId => SNMP_Object_Identifier'Access);
if Return_Value_OID_Copy = 0 then
Ada.Text_IO.Put_Line ("Failed to copy object identifier.");
else
Ada.Text_IO.Put_Line ("Copied object identifier.");
-- Construct variable bindings entry
Variable_Bindings_Entry.value.asnType := Win32.Snmp.ASN_NULL;
-- Construct variable bindings
Variable_Bindings.len := 1;
Variable_Bindings.list := Variable_Bindings_Entry'Unchecked_Access;
Return_Value_Request := Win32.Mgmtapi.SnmpMgrRequest
(session => SNMP_Session,
requestType => Win32.Snmp.ASN_RFC1157_GETREQUEST,
variableBindings => Variable_Bindings'Access,
errorStatus => Error_Status'Access,
errorIndex => Error_Index'Access);
if Return_Value_Request = 0 then
Ada.Text_IO.Put_Line ("Failed to send request.");
else
Ada.Text_IO.Put_Line ("Sent request.");
Ada.Text_IO.Put_Line ("Type is:" & Win32.BYTE'Image (Variable_Bindings.list.value.asnType));
case Variable_Bindings.list.value.asnType is
when Win32.Snmp.ASN_INTEGER =>
Ada.Text_IO.Put_Line (Integer'Image (Integer (Variable_Bindings.list.value.asnValue.number)));
when Win32.Snmp.ASN_OCTETSTRING =>
Ada.Text_IO.Put_Line (Interfaces.C.Strings.Value (Win32.To_Chars_Ptr (To_PCSTR (Variable_Bindings.list.value.asnValue.string.stream))));
when Win32.Snmp.ASN_RFC1155_COUNTER =>
Ada.Text_IO.Put_Line (Counter_Type'Image (Counter_Type (Variable_Bindings.list.value.asnValue.counter)));
when Win32.Snmp.ASN_RFC1155_GAUGE =>
Ada.Text_IO.Put_Line (Gauge_Type'Image (Gauge_Type (Variable_Bindings.list.value.asnValue.counter)));
when Win32.Snmp.ASN_RFC1155_TIMETICKS =>
Ada.Text_IO.Put_Line (Duration'Image (Duration (Variable_Bindings.list.value.asnValue.ticks) / 100));
when others =>
Ada.Text_IO.Put_Line ("Unsupported type.");
end case;
-- Convert object identifier to string
Convert_OID_To_String : declare
OID_String_Win32 : aliased Win32.LPSTR;
begin
Return_Value_OID_To_String_Conversion := Win32.Mgmtapi.SnmpMgrOidToStr
(oid => Variable_Bindings.list.name'Unrestricted_Access,
string => OID_String_Win32'Unchecked_Access);
if Return_Value_OID_To_String_Conversion = 0 then
Ada.Text_IO.Put_Line ("Failed to convert object identifier to string.");
else
Ada.Text_IO.Put_Line (Interfaces.C.Strings.Value (Win32.To_Chars_Ptr (OID_String_Win32)));
end if;
SnmpUtilMemFree (To_LPVOID (OID_String_Win32));
end Convert_OID_To_String;
-- Free memory
SnmpUtilOidFree (SNMP_Object_Identifier'Access);
SnmpUtilVarBindFree (Variable_Bindings_Entry'Access);
SnmpUtilVarBindListFree (Variable_Bindings'Access);
Interfaces.C.Strings.Free (IP_Address_C);
Interfaces.C.Strings.Free (Community_String_C);
Interfaces.C.Strings.Free (SNMP_Object_Identifier_C);
end if;
end if;
end if;
end Send_Request;
Close_Session : declare
Return_Value : constant Win32.BOOL := Win32.Mgmtapi.SnmpMgrClose (SNMP_Session);
begin
if Return_Value = 0 then
Ada.Text_IO.Put_Line ("Failed to close session.");
else
Ada.Text_IO.Put_Line ("Closed session.");
end if;
end Close_Session;
end if;
end SNMP_Example;