net-snmp的片段源码分析

snmp 代理端扩展源码分析
2008-05-05 17:53


#include
#include
#include

#if HAVE_STDLIB_H
#include
#endif

#if TIME_WITH_SYS_TIME

# ifdef WIN32
# include
# else
# include
# endif
# include

#else
# if HAVE_SYS_TIME_H
# include
# else
# include
# endif

#endif


#include "util_funcs.h"
包含自己的头文件
#include "Display_time.h"

#define EXAMPLE_STR_LEN 300
#define EXAMPLE_STR_DEFAULT "life the universe andeverything"
int 
                      example_int = 42;
char                      example_str[EXAMPLE_STR_LEN];

void                      example_parse_config_exampleint(const char *token, char*cptr);
void                      example_parse_config_examplestr(const char *token, char*cptr);
void                      example_free_config_exampleint(void);
void                      example_free_config_examplestr(void);

这个数组的类型是struct variableN, 其中N是这个数组中OID号的最长的数,
即:结构体最后一个成员(这个成员是个数组)定义了MIB Tree OID的底层数字。
      N定义了MIB TreeOID的底层的层数(也就是这个数组的长度)。
      所有有效的N数字都定义在了文件中。

struct variableN类型成员的说明:
      1):FoxmailINT:这个magic number是在自己的头文件Display_time.h中宏定义,
                                    这个参数被用来传递给CallBack 例程,用来决定那个object被查询。
      2):ASN_INTEGER:这个参数说明了object的类型,所有有效的类型在snmp_impl.h文件中列表说明。
      3):RONLY:这个参数说明了object是否能够被set。
      4):var_foxmail:当有object被查询时,这个CallBack 例程被调用。
                              一般的情况下,同一个文件中的所有的object使用相同的allBack 例程。
      5):1:MIBTree OID的底层数字的层数。(这个数字决定了struct variableN中的N)
      6):{1}:MIBTree OID的底层数字。

struct variable2 example_variables[] = {
      {EXAMPLESTRING, ASN_OCTET_STR, RONLY, var_example, 1, {1}},
      {EXAMPLEINTEGER, ASN_INTEGER, RWRITE, var_example, 2, {2,1}},
      {EXAMPLEOBJECTID, ASN_OBJECT_ID, RONLY, var_example, 2, {2,2}},
      {EXAMPLETIMETICKS, ASN_TIMETICKS, RONLY, var_example, 1,{3}},
      {EXAMPLEIPADDRESS, ASN_IPADDRESS, RONLY, var_example, 1,{4}},
      {EXAMPLECOUNTER, ASN_COUNTER, RONLY, var_example, 1, {5}},
      {EXAMPLEGAUGE, ASN_GAUGE, RONLY, var_example, 1, {6}},
      {EXAMPLETRIGGERTRAP, ASN_INTEGER, RWRITE, var_example, 1,{7}},
      {EXAMPLETRIGGERTRAP2, ASN_INTEGER, RWRITE, var_example, 1,{8}}
};

下面这个数组定义了MIB Tree OID的顶层数字。
oid                        example_variables_oid[] = { 1, 3, 6, 1, 4, 1, 2021, 254 };



这个例程在Agent程序开始的时候被调用,用来初始化可能被查询的Object。
void init_example(void)
{
            注册我们自己的MIBTree,以便Agent查询的时候能够处理。
            参数:
                  1)descr:      描述这个MIB Tree
                  2)var:          变量结构体,类型struct variableN。
                  3)vartype:类型struct variableN
                  4)theoid:    MIB Tree的顶层数字
      REGISTER_MIB("example", example_variables, variable2,
                                example_variables_oid);

            把example_str变量设上默认字符串。example_int已经在上面初始化了。
      strncpy(example_str, EXAMPLE_STR_DEFAULT, EXAMPLE_STR_LEN);

      * Registerconfig handlers for the two objects that can be set
        * via configuration file directive
      snmpd_register_config_handler("exampleint",
                                                                  example_parse_config_exampleint,
                                                                  example_free_config_exampleint,
                                                                  "exampleint value");
      snmpd_register_config_handler("examplestr",
                                                                  example_parse_config_examplestr,
                                                                  example_free_config_examplestr,
                                                                  "examplestr value");
      snmpd_register_config_handler("examplestring",
                                                                  example_parse_config_examplestr,
                                                                  example_free_config_examplestr,
                                                                  "examplestring value");

            我们经常需要读取内核中的数据,我们需要在这里进行一些必要的初始化。
            以加快我们读取这些内核信息的速度,快速反应查询请求。
     

}


配置文件处理函数
void
example_parse_config_exampleint(const char *token, char*cptr)
{
      example_int= atoi(cptr);
}
void
example_parse_config_examplestr(const char *token, char*cptr)
{
            必须确保字符串长度小于分配的空间。
      if(strlen(cptr) < EXAMPLE_STR_LEN)
              strcpy(example_str, cptr);
      else {
            如果需要的话,截断这个字符串。
              strncpy(example_str, cptr, EXAMPLE_STR_LEN - 4);
              example_str[EXAMPLE_STR_LEN - 4] = 0;
              strcat(example_str, "...");
              example_str[EXAMPLE_STR_LEN - 1] = 0;
          }
}

当关闭Agent时需要的清除工作。
void
example_free_config_exampleint(void)
{
}

void
example_free_config_examplestr(void)
{
}


当有请求访问这个MIB Tree的object时,就会调用这个处理函数。
参数:
      1)vp          被请求访问的object的example_variables的入口地址
      2)name      被请求访问的object的OID
      3)lengthOID的长度
      4)exact    指示这个request是“exact”(GET/SET)请求,还是“inexact”(GETNEXT/GETBULK)请求
四个参数被用来返回信息:
      1)name                        被请求访问的object的OID
      2)length                  OID的长度
      3)var_len                  返回应答的长度
      4)write_method    被请求访问的object的SET函数的指针

u_char *
var_example(struct variable *vp,
                      oid * name,
                      size_t * length,
                      int exact, size_t * var_len, WriteMethod ** write_method)
{
            从这个函数返回的值必须是一个static data的指针,这样才能够从函数外来访问。
           
      staticchar        string[EXAMPLE_STR_LEN];     
      staticoid          oid_ret[8];
      staticlong        long_ret;   

            在进行应答请求之前,需要检查这个请求object OID是否是一个有效的OID。
            header_generic()函数能够用来检查scalar objects。
            header_simple_table()函数能够用来检查simple table。
            这些函数也当检查正确时,设置默认的返回值。
      * The nameand length are set suitably for the current object,
        * var_len assumes that the result is an integer of some form,
        * and write_method assumes that the object cannot be set.

      DEBUGMSGTL(("example", "var_example entered\n"));
      if(header_generic(vp, name, length, exact, var_len, write_method)==
              MATCH_FAILED)
              return NULL;


            我们使用structvariableN结构体中的magicnumber来决定那个object被请求。           
      switch(vp->magic) {
      caseEXAMPLESTRING:
              sprintf(string, example_str);
                  在上面时假设返回值是integer,但是并不是,所以需要重新设置var_len。
              *var_len = strlen(string);
              return (u_char *) string;

      caseEXAMPLEINTEGER:
                  这种情况,上面的假设的长度是正确的,但是这个object是可以写的,所以需要设置write_method。
              long_ret = example_int;
              *write_method = write_exampleint;
              return (u_char *) & long_ret;

      caseEXAMPLEOBJECTID:
              oid_ret[0] = 1;
              oid_ret[1] = 3;
              oid_ret[2] = 6;
              oid_ret[3] = 1;
              oid_ret[4] = 4;
              oid_ret[5] = oid_ret[6] = oid_ret[7] = 42;
                  这种情况,上面的假设的长度是错误的。
              *var_len = 8 * sizeof(oid);
              return (u_char *) oid_ret;

      caseEXAMPLETIMETICKS:
                  这种情况,上面的假设的长度是正确的,直接返回。
              long_ret = 363136200;   
              return (u_char *) & long_ret;

      caseEXAMPLEIPADDRESS:
              long_ret = ntohl(INADDR_LOOPBACK);
              return (u_char *) & long_ret;

      caseEXAMPLECOUNTER:
              long_ret = 42;
              return (u_char *) & long_ret;

      caseEXAMPLEGAUGE:
              long_ret =42;                 
              return (u_char *) & long_ret;

      caseEXAMPLETRIGGERTRAP:
                  这个object是只能够写的“write-only”。
                  它的作用是只能够产生一个“trap”,当读它的时候只能够返回0。
              long_ret = 0;
              *write_method = write_exampletrap;
              return (u_char *) & long_ret;

      caseEXAMPLETRIGGERTRAP2:
                  这个object是只能够写的“write-only”。
                  它的作用是只能够产生一个SNMP v2版本的“trap”,当读它的时候只能够返回0。

              long_ret = 0;
              *write_method = write_exampletrap2;
              return (u_char *) & long_ret;

      default:
                  这种情况,报告一个错误,并把错误写入log。
              DEBUGMSGTL(("snmpd", "unknown sub-id %d inexamples/var_example\n",
                                      vp->magic));
      }
      returnNULL;
}

当某个object是可写的时候,需要设置SET处理例程。

int
write_exampleint(int action,
                                u_char * var_val,
                                u_char var_val_type,
                                size_t var_val_len,
                                u_char * statP, oid * name, size_t name_len)
{
      定义一个允许访问的最大数值,它是任意的。
#define MAX_EXAMPLE_INT 100
      staticlong        intval;
      staticlong        old_intval;

      switch(action) {
      caseRESERVE1:
                        检查要设置的值是否符合条件。
              if (var_val_type != ASN_INTEGER) {
                      DEBUGMSGTL(("example", "%x not integer type", var_val_type));
                      return SNMP_ERR_WRONGTYPE;
                          }
              if (var_val_len > sizeof(long)) {
                      DEBUGMSGTL(("example", "wrong length %x", var_val_len));
                      return SNMP_ERR_WRONGLENGTH;
                                }

              intval = *((long *) var_val);
              if (intval > MAX_EXAMPLE_INT) {
                      DEBUGMSGTL(("example", "wrong value %x", intval));
                      return SNMP_ERR_WRONGVALUE;
                          }
              break;

      caseRESERVE2:
              break;

      caseFREE:
              break;

      caseACTION:
                  按照请求设置数值,但是这个请求可能被撤销,所以需要保存原来的值。
              old_intval = example_int;
              example_int = intval;
              break;

      caseUNDO:
                  撤销上一个请求,恢复原来的值。
              example_int = old_intval;
              break;

      caseCOMMIT:
              break;

      }
      returnSNMP_ERR_NOERROR;
}




int
write_exampletrap(int action,
                                  u_char * var_val,
                                  u_char var_val_type,
                                  size_t var_val_len,
                                  u_char * statP, oid * name, size_t name_len)
{
      long                      intval;

      DEBUGMSGTL(("example", "write_exampletrap entered:action=%d\n",
                              action));
      switch(action) {
      caseRESERVE1:
              if (var_val_type != ASN_INTEGER) {
                      DEBUGMSGTL(("example", "%x not integer type", var_val_type));
                      return SNMP_ERR_WRONGTYPE;
                          }
              if (var_val_len > sizeof(long)) {
                      DEBUGMSGTL(("example", "wrong length %x", var_val_len));
                      return SNMP_ERR_WRONGLENGTH;
                          }

              intval = *((long *) var_val);
              if (intval != 1) {
                      DEBUGMSGTL(("example", "wrong value %x", intval));
                      return SNMP_ERR_WRONGVALUE;
                              }
              break;

      caseRESERVE2:
              break;

      caseFREE:
              break;

      caseACTION:
              break;

      caseUNDO:
              break;

      caseCOMMIT:
                  产生一个“trap”
              DEBUGMSGTL(("example", "write_exampletrap sending thetrap\n",
                                      action));
              send_easy_trap(SNMP_TRAP_ENTERPRISESPECIFIC, 99);
              DEBUGMSGTL(("example", "write_exampletrap trap sent\n",action));
              break;

      }
      returnSNMP_ERR_NOERROR;
}



int
write_exampletrap2(int action,
                                    u_char * var_val,
                                    u_char var_val_type,
                                    size_t var_val_len,
                                    u_char * statP, oid * name, size_t name_len)
{
      long                      intval;

      oid                        objid_snmptrap[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0};       
      oid                        demo_trap[] = { 1, 3, 6, 1, 4, 1, 2021, 13, 990 };
      oid                        example_string_oid[] =
              { 1, 3, 6, 1, 4, 1, 2021, 254, 1, 0 };
      staticnetsnmp_variable_list var_trap;
      staticnetsnmp_variable_list var_obj;

      DEBUGMSGTL(("example", "write_exampletrap2 entered:action=%d\n",
                              action));
      switch(action) {
      caseRESERVE1:
              if (var_val_type != ASN_INTEGER) {
                      DEBUGMSGTL(("example", "%x not integer type", var_val_type));
                      return SNMP_ERR_WRONGTYPE;
                          }
              if (var_val_len > sizeof(long)) {
                      DEBUGMSGTL(("example", "wrong length %x", var_val_len));
                      return SNMP_ERR_WRONGLENGTH;
                          }

              intval = *((long *) var_val);
              if (intval != 1) {
                      DEBUGMSGTL(("example", "wrong value %x", intval));
                      return SNMP_ERR_WRONGVALUE;
                              }
              break;

      caseRESERVE2:
              break;

      caseFREE:
              break;

      caseACTION:
              break;

      caseUNDO:
              break;

      caseCOMMIT:
                  产生一个 SNMPv2版本的“trap”

              var_trap.next_variable =&var_obj;         
              var_trap.name = objid_snmptrap;
              var_trap.name_length = sizeof(objid_snmptrap) /sizeof(oid);     
              var_trap.type = ASN_OBJECT_ID;
              var_trap.val.objid = demo_trap;
              var_trap.val_len =sizeof(demo_trap);   


              var_obj.next_variable =NULL;   
              var_obj.name = example_string_oid;
              var_obj.name_length = sizeof(example_string_oid) /sizeof(oid);
              var_obj.type =ASN_OCTET_STR;   
              var_obj.val.string =example_str;           
              var_obj.val_len = strlen(example_str);
              DEBUGMSGTL(("example", "write_exampletrap2 sending the v2trap\n",
                                      action));
              send_v2trap(&var_trap);
              DEBUGMSGTL(("example", "write_exampletrap2 v2 trap sent\n",
                                      action));

              break;

            }
      returnSNMP_ERR_NOERROR;
}






REGISTER_MIB()宏定义最终调用的是netsnmp_register_old_api函数。

里面用到了这个结构体。
typedef struct netsnmp_handler_registration_s {

     
              char                    *handlerName;
     
              char                    *contextName;

             
              oid                      *rootoid;
              size_t                  rootoid_len;
             
              netsnmp_mib_handler *handler;
              int                        modes;

             
              int                        priority;
              int                        range_subid;
              oid                        range_ubound;
              int                        timeout;
              int                        global_cacheid;
             
              void*                  my_reg_void;

} netsnmp_handler_registration;



在调用netsnmp_register_handler(reginfo)函数注册netsnmp_handler_registration类型的reginfo变量。

netsnmp_register_handler()在agent/agent_handler.c文件中定义。
有调用netsnmp_register_mib()函数
这个函数构建一个netsnmp_subtree 类型的变量subtree进行注册。

typedef struct netsnmp_subtree_s {
      oid              *name_a;
      u_char                  namelen;     
      oid                      *start_a;     
      u_char                  start_len;
      oid                      *end_a;
      u_char                  end_len;     
      structvariable *variables;
      int                        variables_len;         
      int                        variables_width;     
      char                    *label_a;     
      netsnmp_session *session;
      u_char                  flags;
      u_char                  priority;
      int                        timeout;
      structnetsnmp_subtree_s*next;           
      structnetsnmp_subtree_s*prev;           
      structnetsnmp_subtree_s*children;   
      int                        range_subid;
      oid                        range_ubound;
      netsnmp_handler_registration*reginfo;         
      int                        cacheid;
      int                        global_cacheid;
} netsnmp_subtree;

调用这个函数netsnmp_subtree_load()进行注册。

你可能感兴趣的:(SNMP)