Search code examples
c++encodingfloating-pointsnmp

SNMP: Cannot create/set variable, Wrong Encoding


My first question here ;) I am stuck with trying to set a value on a device with SNMP protocol by using SNMP++ library (http://www.agentpp.com/doc/snmp++3.x/index.html). When I check the value with visual MIB browser, it is shown as Opaque (on device it is, in fact, a float).

So, the current value of the variable is 1.0 (which is represented as an Octed String as 9F 78 04 3F 80 00 00, no idea why first 4 hex-pairs are this way, but 3F 80 00 00 is exactly 1.0 in floatish). I have modified snmpSet console example a little bit, so now when I want to set the value, I do as follows:

(inside determine_vb(...) function)

case sNMP_SYNTAX_OPAQUE:
{
  string str;
  cout << "Opaque\n";
  cout << "Please enter new value: ";
  cin >> str;
  // float value_float = atof(str.c_str());
  const char * value_char = str.c_str();
  vb.set_value(value_char);
  return true;
}

(here you have full .cpp file) http://pastebin.com/8sLTyP8D

Unfortunately, setting data for vb this way does not seem to work, since setting a parameter gives me following error:

Set Status = SNMP: Cannot create/set variable, Wrong Encoding

Does anyone of you have any idea how to properly encode a float for a SNMP query, so it will be accepted?

Best regards! Filip


Solution

  • For anyone looking for the answer, I have finally found a solution, and it required conversions, string to float and the other way around:

    static const unsigned char * convertFloatToSnmpOpaqueFloat(float valueToBeConverted) {
    
        // Reinterpret floating point value as 4-byte array of unsigned chars
        const char * reinterpretedFloat = reinterpret_cast<const char *> (&valueToBeConverted);
    
        // This prefix is used by SNMP to determine that we are using floating-point number.
        // Check ASN1 standard for details. 9F78 = FLOATTYPE, 04 = length
        std::string stringToBeReturned = "";
        stringToBeReturned += '\x9F';
        stringToBeReturned += '\x78';
        stringToBeReturned += '\x04';
        // We have to reverse the order of bytes to get it right
        for (int i = sizeof (float) - 1; i >= 0; --i) {
        //for (int i = 0; i < sizeof (float); ++i) {
            stringToBeReturned = stringToBeReturned + reinterpretedFloat[i];
        }
        const unsigned char * uCharToBeReturned = (const unsigned char *) stringToBeReturned.c_str();
        return (const unsigned char *) stringToBeReturned.c_str();
    }
    
    static float convertSnmpOpaqueFloatToFloat(const std::string & valueToBeConverted) {
        float floatToBeReturned;
        unsigned char * reinterpretedFloat = reinterpret_cast<unsigned char *> (&floatToBeReturned);
        int one, two, three, four;
        std::sscanf(valueToBeConverted.c_str(), "%*X %*X %*X %X %X %X %X", &one, &two, &three, &four);
        reinterpretedFloat[0] = four;
        reinterpretedFloat[1] = three;
        reinterpretedFloat[2] = two;
        reinterpretedFloat[3] = one;
        return floatToBeReturned;
    }