table_container.c
上传用户:wxp200602
上传日期:2007-10-30
资源大小:4028k
文件大小:22k
- /*
- * table_container.c
- * $Id: table_container.c,v 1.13.2.1 2005/10/07 20:42:29 rstory Exp $
- */
- #include <net-snmp/net-snmp-config.h>
- #if HAVE_STRING_H
- #include <string.h>
- #else
- #include <strings.h>
- #endif
- #include <net-snmp/net-snmp-includes.h>
- #include <net-snmp/agent/net-snmp-agent-includes.h>
- #include <net-snmp/agent/table.h>
- #include <net-snmp/agent/table_container.h>
- #include <net-snmp/library/container.h>
- #include <net-snmp/library/snmp_assert.h>
- #if HAVE_DMALLOC_H
- #include <dmalloc.h>
- #endif
- /*
- * snmp.h:#define SNMP_MSG_INTERNAL_SET_BEGIN -1
- * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE1 0
- * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE2 1
- * snmp.h:#define SNMP_MSG_INTERNAL_SET_ACTION 2
- * snmp.h:#define SNMP_MSG_INTERNAL_SET_COMMIT 3
- * snmp.h:#define SNMP_MSG_INTERNAL_SET_FREE 4
- * snmp.h:#define SNMP_MSG_INTERNAL_SET_UNDO 5
- */
- /*
- * PRIVATE structure for holding important info for each table.
- */
- typedef struct container_table_data_s {
- /** registration info for the table */
- netsnmp_table_registration_info *tblreg_info;
- /** container for the table rows */
- netsnmp_container *table;
- /*
- * mutex_type lock;
- */
- /* what type of key do we want? */
- char key_type;
- } container_table_data;
- /** @defgroup table_container table_container: Helps you implement a table when data can be found via a netsnmp_container.
- * @ingroup table
- *
- * The table_container handler is used (automatically) in conjuntion
- * with the @link table table@endlink handler.
- *
- * This handler will use the index information provided by
- * the @link table @endlink handler to find the row needed to process
- * the request.
- *
- * The container must use one of 3 key types. It is the sub-handler's
- * responsibility to ensure that the container and key type match (unless
- * neither is specified, in which case a default will be used.)
- *
- * The current key types are:
- *
- * TABLE_CONTAINER_KEY_NETSNMP_INDEX
- * The container should do comparisons based on a key that may be cast
- * to a netsnmp index (netsnmp_index *). This index contains only the
- * index portion of the OID, not the entire OID.
- *
- * TABLE_CONTAINER_KEY_VARBIND_INDEX
- * The container should do comparisons based on a key that may be cast
- * to a netsnmp variable list (netsnmp_variable_list *). This variable
- * list will contain one varbind for each index component.
- *
- * TABLE_CONTAINER_KEY_VARBIND_RAW (NOTE: unimplemented)
- * While not yet implemented, future plans include passing the request
- * varbind with the full OID to a container.
- *
- * If a key type is not specified at registration time, the default key type
- * of TABLE_CONTAINER_KEY_NETSNMP_INDEX will be used. If a container is
- * provided, or the handler name is aliased to a container type, the container
- * must use a netsnmp index.
- *
- * If no container is provided, a lookup will be made based on the
- * sub-handler's name, or if that isn't found, "table_container". The
- * table_container key type will be netsnmp_index.
- *
- * The container must, at a minimum, implement find and find_next. If a NULL
- * key is passed to the container, it must return the first item, if any.
- * All containers provided by net-snmp fulfil this requirement.
- *
- * This handler will only register to process 'data lookup' modes. In
- * traditional net-snmp modes, that is any GET-like mode (GET, GET-NEXT,
- * GET-BULK) or the first phase of a SET (RESERVE1). In the new baby-steps
- * mode, DATA_LOOKUP is it's own mode, and is a pre-cursor to other modes.
- *
- * When called, the handler will call the appropriate container method
- * with the appropriate key type. If a row was not found, the result depends
- * on the mode.
- *
- * GET Processing
- * An exact match must be found. If one is not, the error NOSUCHINSTANCE
- * is set.
- *
- * GET-NEXT / GET-BULK
- * If no row is found, the column number will be increased (using any
- * valid_columns structure that may have been provided), and the first row
- * will be retrieved. If no first row is found, the processed flag will be
- * set, so that the sub-handler can skip any processing related to the
- * request. The agent will notice this unsatisfied request, and attempt to
- * pass it to the next appropriate handler.
- *
- * SET
- * If the hander did not register with the HANDLER_CAN_NOT_CREATE flag
- * set in the registration modes, it is assumed that this is a row
- * creation request and a NULL row is added to the request's data list.
- * The sub-handler is responsbile for dealing with any row creation
- * contraints and inserting any newly created rows into the container
- * and the request's data list.
- *
- * If a row is found, it will be inserted into
- * the request's data list. The sub-handler may retrieve it by calling
- * netsnmp_container_table_extract_context(request); *
- * NOTE NOTE NOTE:
- *
- * This helper and it's API are still being tested and are subject to change.
- *
- * @{
- */
- static int
- _container_table_handler(netsnmp_mib_handler *handler,
- netsnmp_handler_registration *reginfo,
- netsnmp_agent_request_info *agtreq_info,
- netsnmp_request_info *requests);
- /**********************************************************************
- **********************************************************************
- * *
- * *
- * PUBLIC Registration functions *
- * *
- * *
- **********************************************************************
- **********************************************************************/
- /** register specified callbacks for the specified table/oid.
- */
- netsnmp_mib_handler *
- netsnmp_container_table_handler_get(netsnmp_table_registration_info *tabreg,
- netsnmp_container *container, char key_type)
- {
- container_table_data *tad;
- netsnmp_mib_handler *handler;
- if (NULL == tabreg) {
- snmp_log(LOG_ERR, "bad param in netsnmp_container_table_registern");
- return NULL;
- }
- tad = SNMP_MALLOC_TYPEDEF(container_table_data);
- handler = netsnmp_create_handler("table_container",
- _container_table_handler);
- if((NULL == tad) || (NULL == handler)) {
- if(tad) free(tad); /* SNMP_FREE wasted on locals */
- if(handler) free(handler); /* SNMP_FREE wasted on locals */
- snmp_log(LOG_ERR,
- "malloc failure in netsnmp_container_table_registern");
- return NULL;
- }
- tad->tblreg_info = tabreg; /* we need it too, but it really is not ours */
- if(key_type)
- tad->key_type = key_type;
- else
- tad->key_type = TABLE_CONTAINER_KEY_NETSNMP_INDEX;
- if(NULL == container)
- container = netsnmp_container_find("table_container");
- tad->table = container;
- if (NULL==container->compare)
- container->compare = netsnmp_compare_netsnmp_index;
- if (NULL==container->ncompare)
- container->ncompare = netsnmp_ncompare_netsnmp_index;
-
- handler->myvoid = (void*)tad;
- handler->flags |= MIB_HANDLER_AUTO_NEXT;
-
- return handler;
- }
- int
- netsnmp_container_table_register(netsnmp_handler_registration *reginfo,
- netsnmp_table_registration_info *tabreg,
- netsnmp_container *container, char key_type )
- {
- netsnmp_mib_handler *handler;
- if ((NULL == reginfo) || (NULL == reginfo->handler) || (NULL == tabreg)) {
- snmp_log(LOG_ERR, "bad param in netsnmp_container_table_registern");
- return SNMPERR_GENERR;
- }
- if (NULL==container)
- container = netsnmp_container_find(reginfo->handlerName);
- handler = netsnmp_container_table_handler_get(tabreg, container, key_type);
- netsnmp_inject_handler(reginfo, handler );
- return netsnmp_register_table(reginfo, tabreg);
- }
- /** @} */
- #ifndef DOXYGEN_SHOULD_SKIP_THIS
- /**********************************************************************
- **********************************************************************
- * *
- * *
- * DATA LOOKUP functions *
- * *
- * *
- **********************************************************************
- **********************************************************************/
- NETSNMP_STATIC_INLINE void
- _set_key( container_table_data * tad, netsnmp_request_info *request,
- netsnmp_table_request_info *tblreq_info,
- void **key, netsnmp_index *index )
- {
- if (TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) {
- index->oids = tblreq_info->index_oid;
- index->len = tblreq_info->index_oid_len;
- *key = index;
- }
- else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) {
- *key = tblreq_info->indexes;
- }
- #if 0
- else if (TABLE_CONTAINER_KEY_VARBIND_RAW == tad->key_type) {
- *key = request->requestvb;
- }
- #endif
- else
- *key = NULL;
- }
- static void *
- _find_next_row(netsnmp_container *c,
- netsnmp_table_request_info *tblreq,
- void * key)
- {
- void *row = NULL;
- if (!c || !tblreq || !tblreq->reg_info ) {
- snmp_log(LOG_ERR,"_find_next_row param errorn");
- return NULL;
- }
- /*
- * table helper should have made sure we aren't below our minimum column
- */
- netsnmp_assert(tblreq->colnum >= tblreq->reg_info->min_column);
- /*
- * if no indexes then use first row.
- */
- if(tblreq->number_indexes == 0) {
- row = CONTAINER_FIRST(c);
- } else {
- if(NULL == key) {
- netsnmp_index index;
- index.oids = tblreq->index_oid;
- index.len = tblreq->index_oid_len;
- row = CONTAINER_NEXT(c, &index);
- }
- else
- row = CONTAINER_NEXT(c, key);
- /*
- * we don't have a row, but we might be at the end of a
- * column, so try the next column.
- */
- if (NULL == row) {
- /*
- * don't set tblreq next_col unless we know there is one,
- * so we don't mess up table handler sparse table processing.
- */
- oid next_col = netsnmp_table_next_column(tblreq);
- if (0 != next_col) {
- tblreq->colnum = next_col;
- row = CONTAINER_FIRST(c);
- }
- }
- }
-
- return row;
- }
- /**
- * deprecated, backwards compatability only
- *
- * expected impact to remove: none
- * - used between helpers, shouldn't have been used by end users
- *
- * replacement: none
- * - never should have been a public method in the first place
- */
- netsnmp_index *
- netsnmp_table_index_find_next_row(netsnmp_container *c,
- netsnmp_table_request_info *tblreq)
- {
- return _find_next_row(c, tblreq, NULL );
- }
- NETSNMP_STATIC_INLINE void
- _data_lookup(netsnmp_handler_registration *reginfo,
- netsnmp_agent_request_info *agtreq_info,
- netsnmp_request_info *request, container_table_data * tad)
- {
- netsnmp_index *row = NULL;
- netsnmp_table_request_info *tblreq_info;
- netsnmp_variable_list *var;
- netsnmp_index index;
- void *key;
- var = request->requestvb;
- DEBUGIF("table_container") {
- DEBUGMSGTL(("table_container", " data_lookup oid:"));
- DEBUGMSGOID(("table_container", var->name, var->name_length));
- DEBUGMSG(("table_container", "n"));
- }
- /*
- * Get pointer to the table information for this request. This
- * information was saved by table_helper_handler.
- */
- tblreq_info = netsnmp_extract_table_info(request);
- /** the table_helper_handler should enforce column boundaries. */
- netsnmp_assert((NULL != tblreq_info) &&
- (tblreq_info->colnum <= tad->tblreg_info->max_column));
-
- if ((agtreq_info->mode == MODE_GETNEXT) ||
- (agtreq_info->mode == MODE_GETBULK)) {
- /*
- * find the row. This will automatically move to the next
- * column, if necessary.
- */
- _set_key( tad, request, tblreq_info, &key, &index );
- row = _find_next_row(tad->table, tblreq_info, key);
- if (row) {
- /*
- * update indexes in tblreq_info (index & varbind),
- * then update request varbind oid
- */
- if(TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) {
- tblreq_info->index_oid_len = row->len;
- memcpy(tblreq_info->index_oid, row->oids,
- row->len * sizeof(oid));
- netsnmp_update_variable_list_from_index(tblreq_info);
- }
- else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) {
- netsnmp_update_indexes_from_variable_list(tblreq_info);
- }
- if (TABLE_CONTAINER_KEY_VARBIND_RAW != tad->key_type) {
- netsnmp_table_build_oid_from_index(reginfo, request,
- tblreq_info);
- }
- }
- else {
- /*
- * no results found. Flag the request so lower handlers will
- * ignore it, but it is not an error - getnext will move
- * on to another handler to process this request.
- */
- netsnmp_set_request_error(agtreq_info, request, SNMP_ENDOFMIBVIEW);
- DEBUGMSGTL(("table_container", "no row foundn"));
- }
- } /** GETNEXT/GETBULK */
- else {
- _set_key( tad, request, tblreq_info, &key, &index );
- row = CONTAINER_FIND(tad->table, key);
- if (NULL == row) {
- /*
- * not results found. For a get, that is an error
- */
- DEBUGMSGTL(("table_container", "no row foundn"));
- if((agtreq_info->mode != MODE_SET_RESERVE1) || /* get */
- (reginfo->modes & HANDLER_CAN_NOT_CREATE)) { /* no create */
- netsnmp_set_request_error(agtreq_info, request,
- SNMP_NOSUCHINSTANCE);
- }
- }
- } /** GET/SET */
-
- /*
- * save the data and table in the request.
- */
- if (SNMP_ENDOFMIBVIEW != request->status) {
- if (NULL != row)
- netsnmp_request_add_list_data(request,
- netsnmp_create_data_list
- (TABLE_CONTAINER_ROW,
- row, NULL));
- netsnmp_request_add_list_data(request,
- netsnmp_create_data_list
- (TABLE_CONTAINER_CONTAINER,
- tad->table, NULL));
- }
- }
- /**********************************************************************
- **********************************************************************
- * *
- * *
- * netsnmp_table_container_helper_handler() *
- * *
- * *
- **********************************************************************
- **********************************************************************/
- static int
- _container_table_handler(netsnmp_mib_handler *handler,
- netsnmp_handler_registration *reginfo,
- netsnmp_agent_request_info *agtreq_info,
- netsnmp_request_info *requests)
- {
- int rc = SNMP_ERR_NOERROR;
- int oldmode, need_processing = 0;
- container_table_data *tad;
- /** sanity checks */
- netsnmp_assert((NULL != handler) && (NULL != handler->myvoid));
- netsnmp_assert((NULL != reginfo) && (NULL != agtreq_info));
- DEBUGMSGTL(("table_container", "Mode %s, Got request:n",
- se_find_label_in_slist("agent_mode",agtreq_info->mode)));
- /*
- * First off, get our pointer from the handler. This
- * lets us get to the table registration information we
- * saved in get_table_container_handler(), as well as the
- * container where the actual table data is stored.
- */
- tad = (container_table_data *)handler->myvoid;
- /*
- * only do data lookup for first pass
- *
- * xxx-rks: this should really be handled up one level. we should
- * be able to say what modes we want to be called for during table
- * registration.
- */
- oldmode = agtreq_info->mode;
- if(MODE_IS_GET(oldmode) || (MODE_SET_RESERVE1 == oldmode)) {
- netsnmp_request_info *curr_request;
- /*
- * Loop through each of the requests, and
- * try to find the appropriate row from the container.
- */
- for (curr_request = requests; curr_request; curr_request = curr_request->next) {
- /*
- * skip anything that doesn't need processing.
- */
- if (curr_request->processed != 0) {
- DEBUGMSGTL(("table_container", "already processedn"));
- continue;
- }
-
- /*
- * find data for this request
- */
- _data_lookup(reginfo, agtreq_info, curr_request, tad);
- if(curr_request->processed)
- continue;
- ++need_processing;
- } /** for ( ... requests ... ) */
- }
-
- /*
- * send GET instead of GETNEXT to sub-handlers
- * xxx-rks: again, this should be handled further up.
- */
- if ((oldmode == MODE_GETNEXT) && (handler->next)) {
- /*
- * tell agent handlder not to auto call next handler
- */
- handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
- /*
- * if we found rows to process, pretend to be a get request
- * and call handler below us.
- */
- if(need_processing > 0) {
- agtreq_info->mode = MODE_GET;
- rc = netsnmp_call_next_handler(handler, reginfo, agtreq_info,
- requests);
- if (rc != SNMP_ERR_NOERROR) {
- DEBUGMSGTL(("table_container",
- "next handler returned %dn", rc));
- }
- agtreq_info->mode = oldmode; /* restore saved mode */
- }
- }
- return rc;
- }
- /** retrieve the container used by the table_container helper */
- netsnmp_container*
- netsnmp_container_table_container_extract(netsnmp_request_info *request)
- {
- return (netsnmp_container *)
- netsnmp_request_get_list_data(request, TABLE_CONTAINER_CONTAINER);
- }
- /** inserts a newly created table_container entry into a request list */
- void
- netsnmp_container_table_row_insert(netsnmp_request_info *request,
- netsnmp_index *row)
- {
- netsnmp_request_info *req;
- netsnmp_table_request_info *table_info = NULL;
- netsnmp_variable_list *this_index = NULL;
- netsnmp_variable_list *that_index = NULL;
- oid base_oid[] = {0, 0}; /* Make sure index OIDs are legal! */
- oid this_oid[MAX_OID_LEN];
- oid that_oid[MAX_OID_LEN];
- size_t this_oid_len, that_oid_len;
- if (!request)
- return;
- /*
- * We'll add the new row information to any request
- * structure with the same index values as the request
- * passed in (which includes that one!).
- *
- * So construct an OID based on these index values.
- */
- table_info = netsnmp_extract_table_info(request);
- this_index = table_info->indexes;
- build_oid_noalloc(this_oid, MAX_OID_LEN, &this_oid_len,
- base_oid, 2, this_index);
- /*
- * We need to look through the whole of the request list
- * (as received by the current handler), as there's no
- * guarantee that this routine will be called by the first
- * varbind that refers to this row.
- * In particular, a RowStatus controlled row creation
- * may easily occur later in the variable list.
- *
- * So first, we rewind to the head of the list....
- */
- for (req=request; req->prev; req=req->prev)
- ;
- /*
- * ... and then start looking for matching indexes
- * (by constructing OIDs from these index values)
- */
- for (; req; req=req->next) {
- table_info = netsnmp_extract_table_info(req);
- that_index = table_info->indexes;
- build_oid_noalloc(that_oid, MAX_OID_LEN, &that_oid_len,
- base_oid, 2, that_index);
-
- /*
- * This request has the same index values,
- * so add the newly-created row information.
- */
- if (snmp_oid_compare(this_oid, this_oid_len,
- that_oid, that_oid_len) == 0) {
- netsnmp_request_add_list_data(req,
- netsnmp_create_data_list(TABLE_CONTAINER_ROW, row, NULL));
- }
- }
- }
- #ifndef NETSNMP_USE_INLINE
- /** find the context data used by the table_container helper */
- void *
- netsnmp_container_table_row_extract(netsnmp_request_info *request)
- {
- /*
- * NOTE: this function must match in table_container.c and table_container.h.
- * if you change one, change them both!
- */
- return netsnmp_request_get_list_data(request, TABLE_CONTAINER_ROW);
- }
- #endif /* inline */
- #endif /** DOXYGEN_SHOULD_SKIP_THIS */