Logo
Home page Net-SNMP

Archive Search:

Require all words?

Site Search:
Google
Main Page | Modules | Data Structures | File List | Data Fields | Related Pages | Examples

table_container.c

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

Generated on Fri Dec 30 13:47:50 2005 for net-snmp by  doxygen 1.3.9.1

Valid CSS!


Last modified: Thursday, 01-Mar-2007 16:20:01 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.