In the previous tutorial we wrote a simple read-only counter variable. Here we will continue this work and add write support to the simpleCounter variable. Writing to the variable will set it to a new value, and it will continue to count from there.
The updated MIB looks like that:
SIMPLE-MIB DEFINITIONS ::= BEGIN IMPORTS OBJECT-TYPE FROM SNMPv2-SMI enterprises FROM SNMPv2-SMI; simpleCounter OBJECT-TYPE SYNTAX INTEGER ACCESS read-write STATUS current DESCRIPTION "A simple counter which is incremented each time it is queried. Starts with 0." ::={ enterprises 42 1 } END
This is the same as before, but with "ACCESS read-write".
A single SNMP Set request may set multiple variables at once (possibly distributed over multiple subagents), and SNMP guarantees an atomic operation in that case. This means that, should any variable fail to perform the Set operation, no other variable is allowed to perform the set operation either. Therefore, the Set operation is carried out in multiple distinct steps:
To implement these actions, the Variable class provides the methods testset(), commitset(), cleanupset() and undoset() which can be overridden by a concrete implementation.
To implement write support for the SimpleCounter class, we implement all four methods. The testset() implementation allocates an IntegerValue value, which is deallocated by cleanupset() respectively undoset(). This is not very realistic, but it demonstrates the usage of the individual steps.
The testset() function must be overridden by any variable which should be writeable. If it is not overridden, agentXcpp assumes that the variable is read-only (which we exploited in the first, read-only version). Hence, we implement it for our SimpleCounter class by adding the following code to it:
The testset() method receives the value and can check whether setting the variable to this value would work. Here, we don't check the value, but we allocate an IntegerValue to store the old value, which is needed for undoset(). If allocation fails, we return the error resourceUnavailable.
The commitset() method must also be implemented for writeable variables. In the SimpleCounter class, this method sets the internal value and stores the old one, in case undoset() is called:
The cleanupset() method releases old_value again:
If old_value were an IntegerValue (instead of a pointer to IntegerValue) no allocation and deallocation would have been necessary. The cleanupset() method would not be implemented then. In fact, this method is the only one which is optional for writeable variables, while the other methods are mandatory.
The undoset() method must be implemented by each variable and perform a rollback. It is technically possible to omit this method; the compiler has no way to detect a missing implementation. However, it is an error to omit it, and an error will be reported to the master agent if it is missing. For simpleCounter implementation is easy:
It's important to note that the method releases old_value.
Again, we compile and run the subagent. This is exactly the same as in the first tutorial (it is assumed that your system is already setup accordingly):
g++ simpleagent.cpp -o simpleagent -lagentxcpp \ `pkg-config --cflags --libs QtNetwork QtCore`
Next, we start the subagent again:
./simpleagent
Now, we can query the variable:
snmpget -v1 -c rw localhost SIMPLE-MIB::simpleCounter.0
Each time the variable is queried, the counter increments. Now, let's set the counter to, say, 42:
snmpset -v1 -c rw localhost SIMPLE-MIB::simpleCounter.0 i 42
Now, we continue to query it again several times and the counter should continue at 43, further incrementing.
Et voilá: a read-write variable. Now go on and learn how to send notifications!