Indi TIdSNMP : How use SendQuery

2019-08-18 20:18发布

问题:

I made the following routine in c++builder Xe ( listing code 1 ), using the Indi component TIdSNMP to query an agent snmp.

The call to SendQuery failed, the connection is ok but the agent always return nothing.

I also try to query the agent using the method QuickSend ( listing code 2 ) and in this case this second routine work correclty, so I suppose I made some mistake using the first routine.

Can someone tell me where I was wrong in the first routine ?

Best Reagrds, Enzo

Listing 1

  void __fastcall TForm1::LabelSimpleSnmpCallClick(TObject * Sender)
    {
        String s1, s2, hostTarget = Edit_SnmpServer->Text, sysDescr = "1.3.6.1.2.1.1.1.0", sysUpTime = "1.3.6.1.2.1.1.3.0";

        TIdSNMP * clientSnmp = 0;
        TSNMPInfo * infoSnmp = 0;
        std::auto_ptr< TStringList >sl1(new TStringList());
        std::auto_ptr< TStringList >sl2(new TStringList());

        Mylog(Format("Test simple SNMP call on server [%s]", ARRAYOFCONST((hostTarget))));
        try
        {
            __try
            {
                clientSnmp                 = new TIdSNMP(NULL);
                clientSnmp->Host           = hostTarget;
                clientSnmp->Community      = "pubblic";
                clientSnmp->ReceiveTimeout = 6000;
                clientSnmp->Connect();
                if (clientSnmp->Connected())
                {
                    clientSnmp->Query->Clear();
                    clientSnmp->Query->MIBAdd(sysDescr, "");
                    clientSnmp->Query->MIBAdd(sysUpTime, "");
                    clientSnmp->Query->PDUType = PDUGetRequest;
                    clientSnmp->SendQuery();
                    infoSnmp = clientSnmp->Reply;

                    if (infoSnmp->ValueCount > 0)
                    {
                        sl1->Clear();
                        sl2->Clear();
                        sl1->AddStrings(infoSnmp->MIBOID);
                        sl2->AddStrings(infoSnmp->MIBValue);

                        for (int idx = 0; idx < sl1->Count; idx++)
                        {
                            s1 = sl1->Strings[idx];
                            s2 = sl2->Strings[idx];
                            Mylog(Format("Query on [%s] : [%s] => [%s]", ARRAYOFCONST((hostTarget, s1, s2))));
                        }
                    }
                    else
                    {
                        Mylog("*** No anwser *** ");
                    }
                }
                else
                {
                    Mylog("*** No connected *** ");
                }
            }
            __finally
            {
                if (clientSnmp)
                {
                    delete clientSnmp;
                    clientSnmp = 0;
                }
            }
        }
        catch (Exception & ex)
        {
            Mylog(Format("ERROR [%s] ", ARRAYOFCONST((ex.Message))));
        }

    }

Listing 2

void __fastcall TForm1::LabelQuickSendClick(TObject * Sender)
{
    TIdSNMP * clientSnmp = 0;
    String hostTarget    = Edit_SnmpServer->Text, sysDescr = "1.3.6.1.2.1.1.1.0", sysUpTime = "1.3.6.1.2.1.1.3.0", val;

    __try
    {
        clientSnmp                 = new TIdSNMP(NULL);
        clientSnmp->ReceiveTimeout = 6000;
        clientSnmp->QuickSend(sysDescr, "public", hostTarget, val);
        Mylog(Format("Query on [%s] : [%s] => [%s]", ARRAYOFCONST((hostTarget, sysDescr, val))));
        clientSnmp->QuickSend(sysUpTime, "public", hostTarget, val);
        Mylog(Format("Query on [%s] : [%s] => [%s]", ARRAYOFCONST((hostTarget, sysUpTime, val))));
    }
    __finally
    {
        delete clientSnmp;
    }

}

回答1:

In listing 1, you are setting the Community to "pubblic", but in listing 2 you are setting it to "public" instead. That makes a big difference in SNMP.

As for the rest of the code, I would suggest the following changes to simplify the code:

void __fastcall TForm1::LabelSimpleSnmpCallClick(TObject * Sender)
{
    String hostTarget = Edit_SnmpServer->Text;
    String sysDescr = "1.3.6.1.2.1.1.1.0";
    String sysUpTime = "1.3.6.1.2.1.1.3.0";

    Mylog(Format("Test simple SNMP call on server [%s]", ARRAYOFCONST((hostTarget))));
    try
    {
        std::auto_ptr<TIdSNMP> clientSnmp(TIdSNMP(NULL));
        clientSnmp->Host           = hostTarget;
        clientSnmp->Community      = "public";
        clientSnmp->ReceiveTimeout = 6000;

        clientSnmp->Query->PDUType = PDUGetRequest;
        clientSnmp->Query->MIBAdd(sysDescr, "");
        clientSnmp->Query->MIBAdd(sysUpTime, "");

        if (clientSnmp->SendQuery())
        {
            int cnt = clientSnmp->Reply->ValueCount;
            if (cnt > 0)
            {
                for (int idx = 0; idx < cnt; ++idx)
                {
                    String s1 = clientSnmp->Reply->ValueOID[idx];
                    String s2 = clientSnmp->Reply->Value[idx];
                    Mylog(Format("Query on [%s] : [%s] => [%s]", ARRAYOFCONST((hostTarget, s1, s2))));
                }
            }
            else
            {
                Mylog("*** No anwser *** ");
            }
        }
        else
        {
            Mylog("*** Query not sent *** ");
        }
    }
    catch (const Exception & ex)
    {
        Mylog(Format("ERROR [%s] ", ARRAYOFCONST((ex.Message))));
    }
}

If you overload Mylog() to accept a variable number of parameters, you can simplify your logging a little bit:

void __fastcall TForm1::Mylog(const String &Msg)
{
    // use Msg as needed ...
}

void __fastcall TForm1::Mylog(const String &Msg, const TVarRec *Args, int Args_High)
{
    Mylog(Format(Msg, Args, Args_High));
}

void __fastcall TForm1::LabelSimpleSnmpCallClick(TObject * Sender)
{
    String hostTarget = Edit_SnmpServer->Text;
    String sysDescr = "1.3.6.1.2.1.1.1.0";
    String sysUpTime = "1.3.6.1.2.1.1.3.0";

    Mylog("Test simple SNMP call on server [%s]", ARRAYOFCONST((hostTarget)));
    try
    {
        std::auto_ptr<TIdSNMP> clientSnmp(TIdSNMP(NULL));
        clientSnmp->Host           = hostTarget;
        clientSnmp->Community      = "public";
        clientSnmp->ReceiveTimeout = 6000;

        clientSnmp->Query->PDUType = PDUGetRequest;
        clientSnmp->Query->MIBAdd(sysDescr, "");
        clientSnmp->Query->MIBAdd(sysUpTime, "");

        if (clientSnmp->SendQuery())
        {
            int cnt = clientSnmp->Reply->ValueCount;
            if (cnt > 0)
            {
                for (int idx = 0; idx < cnt; ++idx)
                {
                    String s1 = clientSnmp->Reply->ValueOID[idx];
                    String s2 = clientSnmp->Reply->Value[idx];
                    Mylog("Query on [%s] : [%s] => [%s]", ARRAYOFCONST((hostTarget, s1, s2)));
                }
            }
            else
            {
                Mylog("*** No anwser *** ");
            }
        }
        else
        {
            Mylog("*** Query not sent *** ");
        }
    }
    catch (const Exception & ex)
    {
        Mylog("ERROR [%s] ", ARRAYOFCONST((ex.Message)));
    }
}

If you switch to String::vprintf() instead of Format() then you can simplify the logging a bit further:

void __cdecl TForm1::Mylog(const PChar MsgFmt, ...)
{
    String Msg;

    va_list args;
    va_start(args, MsgFmt);
    Msg.vprintf(MsgFmt, args);
    va_end(args);

    // use Msg as needed...
}

void __fastcall TForm1::LabelSimpleSnmpCallClick(TObject * Sender)
{
    String hostTarget = Edit_SnmpServer->Text;
    String sysDescr = "1.3.6.1.2.1.1.1.0";
    String sysUpTime = "1.3.6.1.2.1.1.3.0";

    Mylog("Test simple SNMP call on server [%s]", hostTarget.c_str());
    try
    {
        std::auto_ptr<TIdSNMP> clientSnmp(TIdSNMP(NULL));
        clientSnmp->Host           = hostTarget;
        clientSnmp->Community      = "public";
        clientSnmp->ReceiveTimeout = 6000;

        clientSnmp->Query->PDUType = PDUGetRequest;
        clientSnmp->Query->MIBAdd(sysDescr, "");
        clientSnmp->Query->MIBAdd(sysUpTime, "");

        if (clientSnmp->SendQuery())
        {
            int cnt = clientSnmp->Reply->ValueCount;
            if (cnt > 0)
            {
                for (int idx = 0; idx < cnt; ++idx)
                {
                    String s1 = clientSnmp->Reply->ValueOID[idx];
                    String s2 = clientSnmp->Reply->Value[idx];
                    Mylog("Query on [%s] : [%s] => [%s]", hostTarget.c_str(), s1.c_str(), s2.c_str());
                }
            }
            else
            {
                Mylog("*** No anwser *** ");
            }
        }
        else
        {
            Mylog("*** Query not sent *** ");
        }
    }
    catch (const Exception & ex)
    {
        Mylog("ERROR [%s] ", ex.Message.c_str());
    }
}