1. 程式人生 > >windows下使用net-snmp實現agent擴充套件(二)

windows下使用net-snmp實現agent擴充套件(二)

剛剛實現了int型的get命令,可能更多的情況下,我們更需要的是字串型別的。在實現int型的時候,用到了netsnmp_register_int_instance這個函式,很自然想到如果是string型的,用類似的netsnmp_register_string_instance,或者netsnmp_register_char_instance不就行了?很可惜的是:net-snmp並沒有提供這兩個函式。通過查詢,在net-snmp5.7.1/agent/mibgroup/examples下面,有個watched.c檔案,這裡提供了對字串型別的操作。實際上,net-snmp將string型歸到了scalar型別裡,做了統一的處理。好,看程式碼:

watched.h檔案:

#ifndef EXAMPLES_WATCHED_H
#define EXAMPLES_WATCHED_H

#ifdef __cplusplus
extern "C" {
#endif

void init_watched(void);

#ifdef __cplusplus
}
#endif

#endif /* EXAMPLES_WATCHED_H */

watched.c檔案:

/*
 * start by including the appropriate header files
 */
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include <net-snmp/agent/net-snmp-agent-includes.h>

void init_watched_string(void);

void init_watched(void)
{
    init_watched_string();
}

void init_watched_string(void)
{
    /*
     * the storage for our string. It must be static or allocated.
     * we use static here for simplicity.
     */
    static char my_string[256] = "welcome to vcsky.net!";

    /*
     * the OID we want to register our string at.  This should be a
     * fully qualified instance.  In our case, it's a scalar at:
     * NET-SNMP-EXAMPLES-MIB::netSnmpExampleString.0  (note the trailing
     *  0 which is required for any instantiation of any scalar object)
     */
    oid             my_registration_oid[] =
        { 1, 3, 6, 1, 4, 1, 8072, 2, 1, 3, 0 };

    /*
     * variables needed for registration
     */
    <a name="_a0"></a><a href="http://www.net-snmp.org/dev/agent/structnetsnmp__handler__registration__s.html">netsnmp_handler_registration</a> *reginfo;
    static <a name="_a1"></a><a href="http://www.net-snmp.org/dev/agent/structnetsnmp__watcher__info__s.html">netsnmp_watcher_info</a> watcher_info;
    int watcher_flags;

    /*
     * a debugging statement.  Run the agent with -Dexample_string_instance
     * to see the output of this debugging statement.
     */
    DEBUGMSGTL(("example_string_instance",
                "Initalizing example string instance.  Default value = %s\n",
                my_string));

    /*
     * If we wanted a callback when the value was retrieved or set
     * (even though the details of doing this are handled for you),
     * you could change the NULL pointer below to a valid handler
     * function.
     *
     * Change RWRITE to RONLY for a read-only string.
     */
    reginfo = <a name="a2"></a><a href="http://www.net-snmp.org/dev/agent/group__handler.html#ga537fac61fff7e112e121e5f629eded65">netsnmp_create_handler_registration</a>("my example string", NULL,
                                                  my_registration_oid,
                                                  OID_LENGTH(my_registration_oid),
                                                  HANDLER_CAN_RWRITE);

    /*
     * the three options for a string watcher are:
     *   fixed size string (length never changes)
     *   variable size (length can be 0 - MAX, for some MAX)
     *   c string (length can be 0 - MAX-1 for some max, \0 is not a valid
     *     character in the string, the length is provided by strlen)
     *
     * we'll use a variable length string.
     */
     watcher_flags =WATCHER_MAX_SIZE;
    /*
     * create the watcher info for our string.
     */
    netsnmp_init_watcher_info6(&amp;watcher_info, my_string, strlen(my_string),
                               ASN_OCTET_STR, watcher_flags,
                               sizeof(my_string), NULL);

    /*
     * the line below registers our "my_string" variable above as
     * accessible and makes it writable.
     */
    <a name="a4"></a><a href="http://www.net-snmp.org/dev/agent/group__watcher.html#ga32250edcf6f39dd7376a20699e1c7cd0">netsnmp_register_watched_instance</a>(reginfo, &amp;watcher_info);

    DEBUGMSGTL(("example_string_instance",
                "Done initalizing example string instance\n"));
}

編譯執行(注意在入口函式中將init_nstAgentSubagentObject替換為init_watched)。 開啟cmd,測試一下:snmpget -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0 返回結果:NET-SNMP-MIB::netSnmp.2.1.3.0 = STRING: “welcome to vcsky.net!” snmpset -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0 s “havenzhao” 返回結果:NET-SNMP-MIB::netSnmp.2.1.3.0 = STRING: “havenzhao” OK,沒問題! 接下來,我們想改變my_string這個變數的值,這個值需要從程式的其它地方獲得,這樣才能起到監測的作用。先簡單改變一下試試看,能否正確執行: 修改下watched.c檔案,新增一行為my_string改變值的語句,標紅的程式碼即是。

#include &lt;net-snmp/net-snmp-config.h&gt;
#include &lt;net-snmp/net-snmp-includes.h&gt;
#include &lt;net-snmp/agent/net-snmp-agent-includes.h&gt;

static char my_string[256] = “welcome to vcsky.net!”; //作為全域性變數

/*change_string_value()模擬在其它程式碼中改變要監測的my_string值的函式,此函式可以放在定時器中,或者其它能夠動態改變my_string值的程式碼段裡,以保證獲取的my_string值是變化的。別忘了在標頭檔案watched.h裡宣告*/

void change_string_value()
{
    strcpy(my_string, "haven zhao");
}

void init_watched_string(void);

void init_watched(void)
{
    init_watched_string();
}

void init_watched_string(void)
{
    oid             my_registration_oid[] =
        { 1, 3, 6, 1, 4, 1, 8072, 2, 1, 3, 0 };

    <a name="_a0"></a><a href="http://www.net-snmp.org/dev/agent/structnetsnmp__handler__registration__s.html">netsnmp_handler_registration</a> *reginfo;
    static <a name="_a1"></a><a href="http://www.net-snmp.org/dev/agent/structnetsnmp__watcher__info__s.html">netsnmp_watcher_info</a> watcher_info;
    int watcher_flags;

    DEBUGMSGTL(("example_string_instance",
                "Initalizing example string instance.  Default value = %s\n",
                my_string));

    reginfo = <a name="a2"></a><a href="http://www.net-snmp.org/dev/agent/group__handler.html#ga537fac61fff7e112e121e5f629eded65">netsnmp_create_handler_registration</a>("my example string", NULL,
                                                  my_registration_oid,
                                                  OID_LENGTH(my_registration_oid),
                                                  HANDLER_CAN_RWRITE);

watcher_flags = WATCHER_MAX_SIZE;

netsnmp_init_watcher_info6(&watcher_info, my_string, strlen(my_string), ASN_OCTET_STR, watcher_flags, sizeof(my_string), NULL);

DEBUGMSGTL((“example_string_instance”, “Done initalizing example string instance\n”)); } 為了方便,我們把change_string_value()函式放在入口函式檔案(example-demon.c)的死迴圈裡: while(keep_running) {

/* if you use select(), see snmp_select_info() in snmp_api(3) */ /*           — OR —        */   change_string_value(); //放在這裡了 agent_check_and_process(1); /* 0 == don’t block */ }

再次編譯執行,看看有沒有達到效果:

輸入:snmpget -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0

返回:NET-SNMP-MIB::netSnmp.2.1.3.0 = Hex-STRING: 68 61 76 65 6E 20 7A 68 61 6F 00 76

出現亂碼,沒有成功!

再試試set命令:snmpset -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0 s “haven”

返回:NET-SNMP-MIB::netSnmp.2.1.3.0 = STRING: “haven”

可見set成功!try again,再輸入get命令:snmpget -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0

返回:NET-SNMP-MIB::netSnmp.2.1.3.0 = STRING: “haven”

這次卻成功了。

難道要先set,再get,才行?什麼情況?再試一次!

輸入:snmpset -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0 s “vcsky.net haven zhao”

返回:NET-SNMP-MIB::netSnmp.2.1.3.0 = STRING: “vcsky.net haven zhao”

輸入:snmpget -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0

返回:NET-SNMP-MIB::netSnmp.2.1.3.0 = Hex-STRING: 68 61 76 65 6E 20 7A 68 61 6F 00 61

照樣失敗!

經過反覆測試,好像和字串的長度有關係。改變後的字串與初始化時的字串長度不一致時,總是達不到我們想要的效果。是的,問題就出在這裡!

解決方案:

看這行程式碼:watcher_flags = WATCHER_MAX_SIZE;

就在這個小小的引數上,例子中的WATCHER_MAX_SIZE:variable size (length can be 0 – MAX, for some MAX),If set then the variable data_size_p points to is supposed to hold the current size of the watched object and will be updated on writes.

而我們則需要這個:c string (length can be 0 – MAX-1 for some max, \0 is not a valid  character in the string, the length is provided by strlen),也就是這個:WATCHER_SIZE_STRLEN

好,馬上替換watcher_flags = WATCHER_MAX_SIZE;為watcher_flags = WATCHER_SIZE_STRLEN;

編譯執行,測試:

輸入:snmpget -v1 -c public localhost 1.3.6.1.4.1.8072.2.1.3.0

返回:NET-SNMP-MIB::netSnmp.2.1.3.0 = STRING: “haven zhao”

OK!到此為止,我們終於前進了一步,由get/set一個int型變數,到get/set一個字串型變數,而且這個字串變數,可由外部的程式碼對其進行設定,從而實現了監測變化的字串變數的目的。

這只是單個的變數,可能要監測的變數不只一個,那怎麼辦呢?未完待續: