table_container.c

00001 /*
00002  * table_container.c
00003  * $Id: table_container.c 14169 2006-01-25 16:28:12Z dts12 $
00004  */
00005 
00006 #include <net-snmp/net-snmp-config.h>
00007 
00008 #if HAVE_STRING_H
00009 #include <string.h>
00010 #else
00011 #include <strings.h>
00012 #endif
00013 
00014 #include <net-snmp/net-snmp-includes.h>
00015 #include <net-snmp/agent/net-snmp-agent-includes.h>
00016 
00017 #include <net-snmp/agent/table.h>
00018 #include <net-snmp/agent/table_container.h>
00019 #include <net-snmp/library/container.h>
00020 #include <net-snmp/library/snmp_assert.h>
00021 
00022 /*
00023  * snmp.h:#define SNMP_MSG_INTERNAL_SET_BEGIN        -1 
00024  * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE1     0 
00025  * snmp.h:#define SNMP_MSG_INTERNAL_SET_RESERVE2     1 
00026  * snmp.h:#define SNMP_MSG_INTERNAL_SET_ACTION       2 
00027  * snmp.h:#define SNMP_MSG_INTERNAL_SET_COMMIT       3 
00028  * snmp.h:#define SNMP_MSG_INTERNAL_SET_FREE         4 
00029  * snmp.h:#define SNMP_MSG_INTERNAL_SET_UNDO         5 
00030  */
00031 
00032 /*
00033  * PRIVATE structure for holding important info for each table.
00034  */
00035 typedef struct container_table_data_s {
00036 
00038     netsnmp_table_registration_info *tblreg_info;
00039 
00041    netsnmp_container          *table;
00042 
00043     /*
00044      * mutex_type                lock;
00045      */
00046 
00047    /* what type of key do we want? */
00048    char            key_type;
00049 
00050 } container_table_data;
00051 
00135 static int
00136 _container_table_handler(netsnmp_mib_handler *handler,
00137                          netsnmp_handler_registration *reginfo,
00138                          netsnmp_agent_request_info *agtreq_info,
00139                          netsnmp_request_info *requests);
00140 
00141 static void *
00142 _find_next_row(netsnmp_container *c,
00143                netsnmp_table_request_info *tblreq,
00144                void * key);
00145 
00146 /**********************************************************************
00147  **********************************************************************
00148  *                                                                    *
00149  *                                                                    *
00150  * PUBLIC Registration functions                                      *
00151  *                                                                    *
00152  *                                                                    *
00153  **********************************************************************
00154  **********************************************************************/
00155 
00156 /* ==================================
00157  *
00158  * Container Table API: Table maintenance
00159  *
00160  * ================================== */
00161 
00162 container_table_data *
00163 netsnmp_tcontainer_create_table( const char *name,
00164                                  netsnmp_container *container, long flags )
00165 {
00166     container_table_data *table;
00167 
00168     table = SNMP_MALLOC_TYPEDEF(container_table_data);
00169     if (!table)
00170         return NULL;
00171     if (container)
00172         table->table = container;
00173     else {
00174         table->table = netsnmp_container_find("table_container");
00175         if (!table->table) {
00176             SNMP_FREE(table);
00177             return NULL;
00178         }
00179     }
00180 
00181     if (flags)
00182         table->key_type = flags & 0x03;  /* Use lowest two bits */
00183     else
00184         table->key_type = TABLE_CONTAINER_KEY_NETSNMP_INDEX;
00185 
00186     if (!table->table->compare)
00187          table->table->compare  = netsnmp_compare_netsnmp_index;
00188     if (!table->table->ncompare)
00189          table->table->ncompare = netsnmp_ncompare_netsnmp_index;
00190 
00191     return table;
00192 }
00193 
00194 void
00195 netsnmp_tcontainer_delete_table( container_table_data *table )
00196 {
00197     if (!table)
00198        return;
00199 
00200     if (table->table)
00201        CONTAINER_FREE(table->table);
00202     
00203     SNMP_FREE(table);
00204     return;
00205 }
00206 
00207     /*
00208      * The various standalone row operation routines
00209      *    (create/clone/copy/delete)
00210      * will be specific to a particular table,
00211      *    so can't be implemented here.
00212      */
00213 
00214 int
00215 netsnmp_tcontainer_add_row( container_table_data *table, netsnmp_index *row )
00216 {
00217     if (!table || !table->table || !row)
00218         return -1;
00219     CONTAINER_INSERT( table->table, row );
00220     return 0;
00221 }
00222 
00223 netsnmp_index *
00224 netsnmp_tcontainer_remove_row( container_table_data *table, netsnmp_index *row )
00225 {
00226     if (!table || !table->table || !row)
00227         return NULL;
00228     CONTAINER_REMOVE( table->table, row );
00229     return NULL;
00230 }
00231 
00232 int
00233 netsnmp_tcontainer_replace_row( container_table_data *table,
00234                                 netsnmp_index *old_row, netsnmp_index *new_row )
00235 {
00236     if (!table || !table->table || !old_row || !new_row)
00237         return -1;
00238     netsnmp_tcontainer_remove_row( table, old_row );
00239     netsnmp_tcontainer_add_row(    table, new_row );
00240     return 0;
00241 }
00242 
00243     /* netsnmp_tcontainer_remove_delete_row() will be table-specific too */
00244 
00245 
00246 /* ==================================
00247  *
00248  * Container Table API: MIB maintenance
00249  *
00250  * ================================== */
00251 
00253 netsnmp_mib_handler *
00254 netsnmp_container_table_handler_get(netsnmp_table_registration_info *tabreg,
00255                                     netsnmp_container *container, char key_type)
00256 {
00257     container_table_data *tad;
00258     netsnmp_mib_handler *handler;
00259 
00260     if (NULL == tabreg) {
00261         snmp_log(LOG_ERR, "bad param in netsnmp_container_table_register\n");
00262         return NULL;
00263     }
00264 
00265     tad = SNMP_MALLOC_TYPEDEF(container_table_data);
00266     handler = netsnmp_create_handler("table_container",
00267                                      _container_table_handler);
00268     if((NULL == tad) || (NULL == handler)) {
00269         if(tad) free(tad); /* SNMP_FREE wasted on locals */
00270         if(handler) free(handler); /* SNMP_FREE wasted on locals */
00271         snmp_log(LOG_ERR,
00272                  "malloc failure in netsnmp_container_table_register\n");
00273         return NULL;
00274     }
00275 
00276     tad->tblreg_info = tabreg;  /* we need it too, but it really is not ours */
00277     if(key_type)
00278         tad->key_type = key_type;
00279     else
00280         tad->key_type = TABLE_CONTAINER_KEY_NETSNMP_INDEX;
00281 
00282     if(NULL == container)
00283         container = netsnmp_container_find("table_container");
00284     tad->table = container;
00285 
00286     if (NULL==container->compare)
00287         container->compare = netsnmp_compare_netsnmp_index;
00288     if (NULL==container->ncompare)
00289         container->ncompare = netsnmp_ncompare_netsnmp_index;
00290     
00291     handler->myvoid = (void*)tad;
00292     handler->flags |= MIB_HANDLER_AUTO_NEXT;
00293     
00294     return handler;
00295 }
00296 
00297 int
00298 netsnmp_container_table_register(netsnmp_handler_registration *reginfo,
00299                                  netsnmp_table_registration_info *tabreg,
00300                                  netsnmp_container *container, char key_type )
00301 {
00302     netsnmp_mib_handler *handler;
00303 
00304     if ((NULL == reginfo) || (NULL == reginfo->handler) || (NULL == tabreg)) {
00305         snmp_log(LOG_ERR, "bad param in netsnmp_container_table_register\n");
00306         return SNMPERR_GENERR;
00307     }
00308 
00309     if (NULL==container)
00310         container = netsnmp_container_find(reginfo->handlerName);
00311 
00312     handler = netsnmp_container_table_handler_get(tabreg, container, key_type);
00313     netsnmp_inject_handler(reginfo, handler );
00314 
00315     return netsnmp_register_table(reginfo, tabreg);
00316 }
00317 
00319 netsnmp_container*
00320 netsnmp_container_table_container_extract(netsnmp_request_info *request)
00321 {
00322     return (netsnmp_container *)
00323          netsnmp_request_get_list_data(request, TABLE_CONTAINER_CONTAINER);
00324 }
00325 
00326 #ifndef NETSNMP_USE_INLINE
00327 
00328 void *
00329 netsnmp_container_table_row_extract(netsnmp_request_info *request)
00330 {
00331     /*
00332      * NOTE: this function must match in table_container.c and table_container.h.
00333      *       if you change one, change them both!
00334      */
00335     return netsnmp_request_get_list_data(request, TABLE_CONTAINER_ROW);
00336 }
00338 void *
00339 netsnmp_container_table_extract_context(netsnmp_request_info *request)
00340 {
00341     /*
00342      * NOTE: this function must match in table_container.c and table_container.h.
00343      *       if you change one, change them both!
00344      */
00345     return netsnmp_request_get_list_data(request, TABLE_CONTAINER_ROW);
00346 }
00347 #endif /* inline */
00348 
00350 void
00351 netsnmp_container_table_row_insert(netsnmp_request_info *request,
00352                                    netsnmp_index        *row)
00353 {
00354     netsnmp_request_info       *req;
00355     netsnmp_table_request_info *table_info = NULL;
00356     netsnmp_variable_list      *this_index = NULL;
00357     netsnmp_variable_list      *that_index = NULL;
00358     oid      base_oid[] = {0, 0};       /* Make sure index OIDs are legal! */
00359     oid      this_oid[MAX_OID_LEN];
00360     oid      that_oid[MAX_OID_LEN];
00361     size_t   this_oid_len, that_oid_len;
00362 
00363     if (!request)
00364         return;
00365 
00366     /*
00367      * We'll add the new row information to any request
00368      * structure with the same index values as the request
00369      * passed in (which includes that one!).
00370      *
00371      * So construct an OID based on these index values.
00372      */
00373 
00374     table_info = netsnmp_extract_table_info(request);
00375     this_index = table_info->indexes;
00376     build_oid_noalloc(this_oid, MAX_OID_LEN, &this_oid_len,
00377                       base_oid, 2, this_index);
00378 
00379     /*
00380      * We need to look through the whole of the request list
00381      * (as received by the current handler), as there's no
00382      * guarantee that this routine will be called by the first
00383      * varbind that refers to this row.
00384      *   In particular, a RowStatus controlled row creation
00385      * may easily occur later in the variable list.
00386      *
00387      * So first, we rewind to the head of the list....
00388      */
00389     for (req=request; req->prev; req=req->prev)
00390         ;
00391 
00392     /*
00393      * ... and then start looking for matching indexes
00394      * (by constructing OIDs from these index values)
00395      */
00396     for (; req; req=req->next) {
00397         if (req->processed) 
00398             continue;
00399         
00400         table_info = netsnmp_extract_table_info(req);
00401         that_index = table_info->indexes;
00402         build_oid_noalloc(that_oid, MAX_OID_LEN, &that_oid_len,
00403                           base_oid, 2, that_index);
00404       
00405         /*
00406          * This request has the same index values,
00407          * so add the newly-created row information.
00408          */
00409         if (snmp_oid_compare(this_oid, this_oid_len,
00410                              that_oid, that_oid_len) == 0) {
00411             netsnmp_request_add_list_data(req,
00412                 netsnmp_create_data_list(TABLE_CONTAINER_ROW, row, NULL));
00413         }
00414     }
00415 }
00416 
00418 /**********************************************************************
00419  **********************************************************************
00420  *                                                                    *
00421  *                                                                    *
00422  * DATA LOOKUP functions                                              *
00423  *                                                                    *
00424  *                                                                    *
00425  **********************************************************************
00426  **********************************************************************/
00427 NETSNMP_STATIC_INLINE void
00428 _set_key( container_table_data * tad, netsnmp_request_info *request,
00429           netsnmp_table_request_info *tblreq_info,
00430           void **key, netsnmp_index *index )
00431 {
00432     if (TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) {
00433         index->oids = tblreq_info->index_oid;
00434         index->len = tblreq_info->index_oid_len;
00435         *key = index;
00436     }
00437     else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) {
00438         *key = tblreq_info->indexes;
00439     }
00440 #if 0
00441     else if (TABLE_CONTAINER_KEY_VARBIND_RAW == tad->key_type) {
00442         *key = request->requestvb;
00443     }
00444 #endif
00445     else
00446         *key = NULL;
00447 }
00448 
00449 
00450 NETSNMP_STATIC_INLINE void
00451 _data_lookup(netsnmp_handler_registration *reginfo,
00452             netsnmp_agent_request_info *agtreq_info,
00453             netsnmp_request_info *request, container_table_data * tad)
00454 {
00455     netsnmp_index *row = NULL;
00456     netsnmp_table_request_info *tblreq_info;
00457     netsnmp_variable_list *var;
00458     netsnmp_index index;
00459     void *key;
00460 
00461     var = request->requestvb;
00462 
00463     DEBUGIF("table_container") {
00464         DEBUGMSGTL(("table_container", "  data_lookup oid:"));
00465         DEBUGMSGOID(("table_container", var->name, var->name_length));
00466         DEBUGMSG(("table_container", "\n"));
00467     }
00468 
00469     /*
00470      * Get pointer to the table information for this request. This
00471      * information was saved by table_helper_handler.
00472      */
00473     tblreq_info = netsnmp_extract_table_info(request);
00475     netsnmp_assert((NULL != tblreq_info) &&
00476                    (tblreq_info->colnum <= tad->tblreg_info->max_column));
00477     
00478     if ((agtreq_info->mode == MODE_GETNEXT) ||
00479         (agtreq_info->mode == MODE_GETBULK)) {
00480         /*
00481          * find the row. This will automatically move to the next
00482          * column, if necessary.
00483          */
00484         _set_key( tad, request, tblreq_info, &key, &index );
00485         row = _find_next_row(tad->table, tblreq_info, key);
00486         if (row) {
00487             /*
00488              * update indexes in tblreq_info (index & varbind),
00489              * then update request varbind oid
00490              */
00491             if(TABLE_CONTAINER_KEY_NETSNMP_INDEX == tad->key_type) {
00492                 tblreq_info->index_oid_len = row->len;
00493                 memcpy(tblreq_info->index_oid, row->oids,
00494                        row->len * sizeof(oid));
00495                 netsnmp_update_variable_list_from_index(tblreq_info);
00496             }
00497             else if (TABLE_CONTAINER_KEY_VARBIND_INDEX == tad->key_type) {
00500                 netsnmp_update_indexes_from_variable_list(tblreq_info);
00501             }
00502 
00503             if (TABLE_CONTAINER_KEY_VARBIND_RAW != tad->key_type) {
00504                 netsnmp_table_build_oid_from_index(reginfo, request,
00505                                                    tblreq_info);
00506             }
00507         }
00508         else {
00509             /*
00510              * no results found. Flag the request so lower handlers will
00511              * ignore it, but it is not an error - getnext will move
00512              * on to another handler to process this request.
00513              */
00514             netsnmp_set_request_error(agtreq_info, request, SNMP_ENDOFMIBVIEW);
00515             DEBUGMSGTL(("table_container", "no row found\n"));
00516         }
00517     } 
00518     else {
00519 
00520         _set_key( tad, request, tblreq_info, &key, &index );
00521         row = CONTAINER_FIND(tad->table, key);
00522         if (NULL == row) {
00523             /*
00524              * not results found. For a get, that is an error
00525              */
00526             DEBUGMSGTL(("table_container", "no row found\n"));
00527             if((agtreq_info->mode != MODE_SET_RESERVE1) || /* get */
00528                (reginfo->modes & HANDLER_CAN_NOT_CREATE)) { /* no create */
00529                 netsnmp_set_request_error(agtreq_info, request,
00530                                           SNMP_NOSUCHINSTANCE);
00531             }
00532         }
00533     } 
00535     /*
00536      * save the data and table in the request.
00537      */
00538     if (SNMP_ENDOFMIBVIEW != request->requestvb->type) {
00539         if (NULL != row)
00540             netsnmp_request_add_list_data(request,
00541                                           netsnmp_create_data_list
00542                                           (TABLE_CONTAINER_ROW,
00543                                            row, NULL));
00544         netsnmp_request_add_list_data(request,
00545                                       netsnmp_create_data_list
00546                                       (TABLE_CONTAINER_CONTAINER,
00547                                        tad->table, NULL));
00548     }
00549 }
00550 
00551 /**********************************************************************
00552  **********************************************************************
00553  *                                                                    *
00554  *                                                                    *
00555  * netsnmp_table_container_helper_handler()                           *
00556  *                                                                    *
00557  *                                                                    *
00558  **********************************************************************
00559  **********************************************************************/
00560 static int
00561 _container_table_handler(netsnmp_mib_handler *handler,
00562                          netsnmp_handler_registration *reginfo,
00563                          netsnmp_agent_request_info *agtreq_info,
00564                          netsnmp_request_info *requests)
00565 {
00566     int             rc = SNMP_ERR_NOERROR;
00567     int             oldmode, need_processing = 0;
00568     container_table_data *tad;
00569 
00571     netsnmp_assert((NULL != handler) && (NULL != handler->myvoid));
00572     netsnmp_assert((NULL != reginfo) && (NULL != agtreq_info));
00573 
00574     DEBUGMSGTL(("table_container", "Mode %s, Got request:\n",
00575                 se_find_label_in_slist("agent_mode",agtreq_info->mode)));
00576 
00577     /*
00578      * First off, get our pointer from the handler. This
00579      * lets us get to the table registration information we
00580      * saved in get_table_container_handler(), as well as the
00581      * container where the actual table data is stored.
00582      */
00583     tad = (container_table_data *)handler->myvoid;
00584 
00585     /*
00586      * only do data lookup for first pass
00587      *
00588      * xxx-rks: this should really be handled up one level. we should
00589      * be able to say what modes we want to be called for during table
00590      * registration.
00591      */
00592     oldmode = agtreq_info->mode;
00593     if(MODE_IS_GET(oldmode) || (MODE_SET_RESERVE1 == oldmode)) {
00594         netsnmp_request_info *curr_request;
00595         /*
00596          * Loop through each of the requests, and
00597          * try to find the appropriate row from the container.
00598          */
00599         for (curr_request = requests; curr_request; curr_request = curr_request->next) {
00600             /*
00601              * skip anything that doesn't need processing.
00602              */
00603             if (curr_request->processed != 0) {
00604                 DEBUGMSGTL(("table_container", "already processed\n"));
00605                 continue;
00606             }
00607             
00608             /*
00609              * find data for this request
00610              */
00611             _data_lookup(reginfo, agtreq_info, curr_request, tad);
00612 
00613             if(curr_request->processed)
00614                 continue;
00615 
00616             ++need_processing;
00617         } 
00618     }
00619     
00620     /*
00621      * send GET instead of GETNEXT to sub-handlers
00622      * xxx-rks: again, this should be handled further up.
00623      */
00624     if ((oldmode == MODE_GETNEXT) && (handler->next)) {
00625         /*
00626          * tell agent handlder not to auto call next handler
00627          */
00628         handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE;
00629 
00630         /*
00631          * if we found rows to process, pretend to be a get request
00632          * and call handler below us.
00633          */
00634         if(need_processing > 0) {
00635             agtreq_info->mode = MODE_GET;
00636             rc = netsnmp_call_next_handler(handler, reginfo, agtreq_info,
00637                                            requests);
00638             if (rc != SNMP_ERR_NOERROR) {
00639                 DEBUGMSGTL(("table_container",
00640                             "next handler returned %d\n", rc));
00641             }
00642 
00643             agtreq_info->mode = oldmode; /* restore saved mode */
00644         }
00645     }
00646 
00647     return rc;
00648 }
00652 /* ==================================
00653  *
00654  * Container Table API: Row operations
00655  *
00656  * ================================== */
00657 
00658 static void *
00659 _find_next_row(netsnmp_container *c,
00660                netsnmp_table_request_info *tblreq,
00661                void * key)
00662 {
00663     void *row = NULL;
00664 
00665     if (!c || !tblreq || !tblreq->reg_info ) {
00666         snmp_log(LOG_ERR,"_find_next_row param error\n");
00667         return NULL;
00668     }
00669 
00670     /*
00671      * table helper should have made sure we aren't below our minimum column
00672      */
00673     netsnmp_assert(tblreq->colnum >= tblreq->reg_info->min_column);
00674 
00675     /*
00676      * if no indexes then use first row.
00677      */
00678     if(tblreq->number_indexes == 0) {
00679         row = CONTAINER_FIRST(c);
00680     } else {
00681 
00682         if(NULL == key) {
00683             netsnmp_index index;
00684             index.oids = tblreq->index_oid;
00685             index.len = tblreq->index_oid_len;
00686             row = CONTAINER_NEXT(c, &index);
00687         }
00688         else
00689             row = CONTAINER_NEXT(c, key);
00690 
00691         /*
00692          * we don't have a row, but we might be at the end of a
00693          * column, so try the next column.
00694          */
00695         if (NULL == row) {
00696             /*
00697              * don't set tblreq next_col unless we know there is one,
00698              * so we don't mess up table handler sparse table processing.
00699              */
00700             oid next_col = netsnmp_table_next_column(tblreq);
00701             if (0 != next_col) {
00702                 tblreq->colnum = next_col;
00703                 row = CONTAINER_FIRST(c);
00704             }
00705         }
00706     }
00707     
00708     return row;
00709 }
00710 
00720 netsnmp_index *
00721 netsnmp_table_index_find_next_row(netsnmp_container *c,
00722                                   netsnmp_table_request_info *tblreq)
00723 {
00724     return _find_next_row(c, tblreq, NULL );
00725 }
00726 
00727 /* ==================================
00728  *
00729  * Container Table API: Index operations
00730  *
00731  * ================================== */
00732 

net-snmpに対してSat Sep 5 13:14:27 2009に生成されました。  doxygen 1.4.7