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_iterator.c

00001 /*
00002  * table_iterator.c 
00003  */
00004 /* Portions of this file are subject to the following copyright(s).  See
00005  * the Net-SNMP's COPYING file for more details and other copyrights
00006  * that may apply:
00007  */
00008 /*
00009  * Portions of this file are copyrighted by:
00010  * Copyright © 2003 Sun Microsystems, Inc. All rights reserved.
00011  * Use is subject to license terms specified in the COPYING file
00012  * distributed with the Net-SNMP package.
00013  */
00014 
00084 #include <net-snmp/net-snmp-config.h>
00085 
00086 #if HAVE_STRING_H
00087 #include <string.h>
00088 #else
00089 #include <strings.h>
00090 #endif
00091 
00092 #include <net-snmp/net-snmp-includes.h>
00093 #include <net-snmp/agent/net-snmp-agent-includes.h>
00094 
00095 #include <net-snmp/agent/table.h>
00096 #include <net-snmp/agent/serialize.h>
00097 #include <net-snmp/agent/table_iterator.h>
00098 #include <net-snmp/agent/stash_cache.h>
00099 
00100 /* ==================================
00101  *
00102  * Iterator API: Table maintenance
00103  *
00104  * ================================== */
00105 
00106     /*
00107      * Iterator-based tables are typically maintained by external
00108      *  code, and this helper is really only concerned with
00109      *  mapping between a walk through this local representation,
00110      *  and the requirements of SNMP table ordering.
00111      * However, there's a case to be made for considering the
00112      *  iterator info structure as encapsulating the table, so
00113      *  it's probably worth defining the table creation/deletion
00114      *  routines from the generic API.
00115      *
00116      * Time will show whether this is a sensible approach or not.
00117      */
00118 netsnmp_iterator_info *
00119 netsnmp_iterator_create_table( Netsnmp_First_Data_Point *firstDP,
00120                                Netsnmp_Next_Data_Point  *nextDP,
00121                                Netsnmp_First_Data_Point *getidx,
00122                                netsnmp_variable_list    *indexes)
00123 {
00124     netsnmp_iterator_info *iinfo =
00125         SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
00126 
00127     if ( !iinfo )
00128         return NULL;
00129 
00130     if ( indexes )
00131         iinfo->indexes = snmp_clone_varbind(indexes);
00132     iinfo->get_first_data_point = firstDP;
00133     iinfo->get_next_data_point  = nextDP;
00134     iinfo->get_row_indexes      = getidx;
00135 
00136     return iinfo;
00137 }
00138 
00139 void
00140 netsnmp_iterator_delete_table( netsnmp_iterator_info *iinfo )
00141 {
00142     if (!iinfo)
00143         return;
00144 
00145     if (iinfo->indexes) {
00146         snmp_free_varbind( iinfo->indexes );
00147         iinfo->indexes = NULL;
00148     }
00149     SNMP_FREE( iinfo );
00150 }
00151 
00152     /*
00153      * The rest of the table maintenance section of the
00154      *   generic table API is Not Applicable to this helper.
00155      *
00156      * The contents of a iterator-based table will be
00157      *  maintained by the table-specific module itself.
00158      */
00159 
00160 /* ==================================
00161  *
00162  * Iterator API: MIB maintenance
00163  *
00164  * ================================== */
00165 
00167 netsnmp_mib_handler *
00168 netsnmp_get_table_iterator_handler(netsnmp_iterator_info *iinfo)
00169 {
00170     netsnmp_mib_handler *me =
00171         netsnmp_create_handler(TABLE_ITERATOR_NAME,
00172                                netsnmp_table_iterator_helper_handler);
00173 
00174     if (!me || !iinfo)
00175         return NULL;
00176 
00177     me->myvoid = iinfo;
00178     return me;
00179 }
00180 
00198 int
00199 netsnmp_register_table_iterator(netsnmp_handler_registration *reginfo,
00200                                 netsnmp_iterator_info *iinfo)
00201 {
00202     reginfo->modes |= HANDLER_CAN_STASH;
00203     netsnmp_inject_handler(reginfo,
00204                            netsnmp_get_table_iterator_handler(iinfo));
00205     if (!iinfo)
00206         return SNMPERR_GENERR;
00207     if (!iinfo->indexes && iinfo->table_reginfo &&
00208                            iinfo->table_reginfo->indexes )
00209         iinfo->indexes = snmp_clone_varbind( iinfo->table_reginfo->indexes );
00210 
00211     return netsnmp_register_table(reginfo, iinfo->table_reginfo);
00212 }
00213 
00227 NETSNMP_INLINE void    *
00228 netsnmp_extract_iterator_context(netsnmp_request_info *request)
00229 {
00230     return netsnmp_request_get_list_data(request, TABLE_ITERATOR_NAME);
00231 }
00232 
00235 NETSNMP_INLINE void
00236 netsnmp_insert_iterator_context(netsnmp_request_info *request, void *data)
00237 {
00238     netsnmp_request_info       *req;
00239     netsnmp_table_request_info *table_info = NULL;
00240     netsnmp_variable_list      *this_index = NULL;
00241     netsnmp_variable_list      *that_index = NULL;
00242     oid      base_oid[] = {0, 0};       /* Make sure index OIDs are legal! */
00243     oid      this_oid[MAX_OID_LEN];
00244     oid      that_oid[MAX_OID_LEN];
00245     size_t   this_oid_len, that_oid_len;
00246 
00247     if (!request)
00248         return;
00249 
00250     /*
00251      * We'll add the new row information to any request
00252      * structure with the same index values as the request
00253      * passed in (which includes that one!).
00254      *
00255      * So construct an OID based on these index values.
00256      */
00257 
00258     table_info = netsnmp_extract_table_info(request);
00259     this_index = table_info->indexes;
00260     build_oid_noalloc(this_oid, MAX_OID_LEN, &this_oid_len,
00261                       base_oid, 2, this_index);
00262 
00263     /*
00264      * We need to look through the whole of the request list
00265      * (as received by the current handler), as there's no
00266      * guarantee that this routine will be called by the first
00267      * varbind that refers to this row.
00268      *   In particular, a RowStatus controlled row creation
00269      * may easily occur later in the variable list.
00270      *
00271      * So first, we rewind to the head of the list....
00272      */
00273     for (req=request; req->prev; req=req->prev)
00274         ;
00275 
00276     /*
00277      * ... and then start looking for matching indexes
00278      * (by constructing OIDs from these index values)
00279      */
00280     for (; req; req=req->next) {
00281         table_info = netsnmp_extract_table_info(req);
00282         that_index = table_info->indexes;
00283         build_oid_noalloc(that_oid, MAX_OID_LEN, &that_oid_len,
00284                           base_oid, 2, that_index);
00285       
00286         /*
00287          * This request has the same index values,
00288          * so add the newly-created row information.
00289          */
00290         if (snmp_oid_compare(this_oid, this_oid_len,
00291                              that_oid, that_oid_len) == 0) {
00292             netsnmp_request_add_list_data(req,
00293                 netsnmp_create_data_list(TABLE_ITERATOR_NAME, data, NULL));
00294         }
00295     }
00296 }
00297 
00298 #define TI_REQUEST_CACHE "ti_cache"
00299 
00300 typedef struct ti_cache_info_s {
00301    oid best_match[MAX_OID_LEN];
00302    size_t best_match_len;
00303    void *data_context;
00304    Netsnmp_Free_Data_Context *free_context;
00305    netsnmp_iterator_info *iinfo;
00306    netsnmp_variable_list *results;
00307 } ti_cache_info;
00308 
00309 static void
00310 netsnmp_free_ti_cache(void *it) {
00311     ti_cache_info *beer = it;
00312     if (!it) return;
00313     if (beer->data_context && beer->free_context) {
00314             (beer->free_context)(beer->data_context, beer->iinfo);
00315     }
00316     if (beer->results) {
00317         snmp_free_varbind(beer->results);
00318     }
00319     free(beer);
00320 }
00321 
00322 /* caches information (in the request) we'll need at a later point in time */
00323 static ti_cache_info *
00324 netsnmp_iterator_remember(netsnmp_request_info *request,
00325                           oid *oid_to_save,
00326                           size_t oid_to_save_len,
00327                           void *callback_data_context,
00328                           void *callback_loop_context,
00329                           netsnmp_iterator_info *iinfo)
00330 {
00331     ti_cache_info *ti_info;
00332 
00333     if (!request || !oid_to_save || oid_to_save_len > MAX_OID_LEN)
00334         return NULL;
00335 
00336     /* extract existing cached state */
00337     ti_info = netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
00338 
00339     /* no existing cached state.  make a new one. */
00340     if (!ti_info) {
00341         ti_info = SNMP_MALLOC_TYPEDEF(ti_cache_info);
00342         netsnmp_request_add_list_data(request,
00343                                       netsnmp_create_data_list
00344                                       (TI_REQUEST_CACHE,
00345                                        ti_info,
00346                                        netsnmp_free_ti_cache));
00347     }
00348 
00349     /* free existing cache before replacing */
00350     if (ti_info->data_context && ti_info->free_context)
00351         (ti_info->free_context)(ti_info->data_context, iinfo);
00352 
00353     /* maybe generate it from the loop context? */
00354     if (iinfo->make_data_context && !callback_data_context) {
00355         callback_data_context =
00356             (iinfo->make_data_context)(callback_loop_context, iinfo);
00357 
00358     }
00359 
00360     /* save data as requested */
00361     ti_info->data_context = callback_data_context;
00362     ti_info->free_context = iinfo->free_data_context;
00363     ti_info->best_match_len = oid_to_save_len;
00364     ti_info->iinfo = iinfo;
00365     if (oid_to_save_len)
00366         memcpy(ti_info->best_match, oid_to_save, oid_to_save_len * sizeof(oid));
00367 
00368     return ti_info;
00369 }    
00370 
00371 #define TABLE_ITERATOR_NOTAGAIN 255
00372 /* implements the table_iterator helper */
00373 int
00374 netsnmp_table_iterator_helper_handler(netsnmp_mib_handler *handler,
00375                                       netsnmp_handler_registration *reginfo,
00376                                       netsnmp_agent_request_info *reqinfo,
00377                                       netsnmp_request_info *requests)
00378 {
00379     netsnmp_table_registration_info *tbl_info;
00380     netsnmp_table_request_info *table_info = NULL;
00381     oid             coloid[MAX_OID_LEN];
00382     size_t          coloid_len;
00383     int             ret;
00384     static oid      myname[MAX_OID_LEN];
00385     size_t          myname_len;
00386     int             oldmode = 0;
00387     netsnmp_iterator_info *iinfo;
00388     int notdone;
00389     netsnmp_request_info *request, *reqtmp = NULL;
00390     netsnmp_variable_list *index_search = NULL;
00391     netsnmp_variable_list *free_this_index_search = NULL;
00392     void           *callback_loop_context = NULL, *last_loop_context;
00393     void           *callback_data_context = NULL;
00394     ti_cache_info  *ti_info = NULL;
00395     int             request_count = 0;
00396     netsnmp_oid_stash_node **cinfo = NULL;
00397     netsnmp_variable_list *old_indexes = NULL, *vb;
00398     netsnmp_table_registration_info *table_reg_info = NULL;
00399     int i;
00400     netsnmp_data_list    *ldata;
00401     
00402     iinfo = (netsnmp_iterator_info *) handler->myvoid;
00403     if (!iinfo || !reginfo || !reqinfo)
00404         return SNMPERR_GENERR;
00405 
00406     tbl_info = iinfo->table_reginfo;
00407 
00408     /*
00409      * copy in the table registration oid for later use 
00410      */
00411     coloid_len = reginfo->rootoid_len + 2;
00412     memcpy(coloid, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid));
00413     coloid[reginfo->rootoid_len] = 1;   /* table.entry node */
00414 
00415     /*
00416      * illegally got here if these functions aren't defined 
00417      */
00418     if (iinfo->get_first_data_point == NULL ||
00419         iinfo->get_next_data_point == NULL) {
00420         snmp_log(LOG_ERR,
00421                  "table_iterator helper called without data accessor functions\n");
00422         return SNMP_ERR_GENERR;
00423     }
00424 
00425     /* preliminary analysis */
00426     switch (reqinfo->mode) {
00427     case MODE_GET_STASH:
00428         cinfo = netsnmp_extract_stash_cache(reqinfo);
00429         table_reg_info = netsnmp_find_table_registration_info(reginfo);
00430 
00431         /* XXX: move this malloc to stash_cache handler? */
00432         reqtmp = SNMP_MALLOC_TYPEDEF(netsnmp_request_info);
00433         reqtmp->subtree = requests->subtree;
00434         table_info = netsnmp_extract_table_info(requests);
00435         netsnmp_request_add_list_data(reqtmp,
00436                                       netsnmp_create_data_list
00437                                       (TABLE_HANDLER_NAME,
00438                                        (void *) table_info, NULL));
00439 
00440         /* remember the indexes that were originally parsed. */
00441         old_indexes = table_info->indexes;
00442         break;
00443 
00444     case MODE_GETNEXT:
00445         for(request = requests ; request; request = request->next) {
00446             if (request->processed)
00447                 continue;
00448             table_info = netsnmp_extract_table_info(request);
00449             if (table_info->colnum < tbl_info->min_column - 1) {
00450                 /* XXX: optimize better than this */
00451                 /* for now, just increase to colnum-1 */
00452                 /* we need to jump to the lowest result of the min_column
00453                    and take it, comparing to nothing from the request */
00454                 table_info->colnum = tbl_info->min_column - 1;
00455             } else if (table_info->colnum > tbl_info->max_column) {
00456                 request->processed = TABLE_ITERATOR_NOTAGAIN;
00457             }
00458 
00459             ti_info =
00460                 netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
00461             if (!ti_info) {
00462                 ti_info = SNMP_MALLOC_TYPEDEF(ti_cache_info);
00463                 netsnmp_request_add_list_data(request,
00464                                               netsnmp_create_data_list
00465                                               (TI_REQUEST_CACHE,
00466                                                ti_info,
00467                                                netsnmp_free_ti_cache));
00468             }
00469 
00470             /* XXX: if no valid requests, don't even loop below */
00471         }
00472         break;
00473     }
00474 
00475     /*
00476      * collect all information for each needed row
00477      */
00478     if (reqinfo->mode == MODE_GET ||
00479         reqinfo->mode == MODE_GETNEXT ||
00480         reqinfo->mode == MODE_GET_STASH ||
00481         reqinfo->mode == MODE_SET_RESERVE1) {
00482         /*
00483          * Count the number of request in the list,
00484          *   so that we'll know when we're finished
00485          */
00486         for(request = requests ; request; request = request->next)
00487             request_count++;
00488         notdone = 1;
00489         while(notdone) {
00490             notdone = 0;
00491 
00492             /* find first data point */
00493             if (!index_search) {
00494                 if (free_this_index_search) {
00495                     /* previously done */
00496                     index_search = free_this_index_search;
00497                 } else {
00498                     table_info = netsnmp_extract_table_info(requests);
00499                     index_search = snmp_clone_varbind(table_info->indexes);
00500                     free_this_index_search = index_search;
00501 
00502                     /* setup, malloc search data: */
00503                     if (!index_search) {
00504                         /*
00505                          * hmmm....  invalid table? 
00506                          */
00507                         snmp_log(LOG_WARNING,
00508                                  "invalid index list or failed malloc for table %s\n",
00509                                  reginfo->handlerName);
00510                         return SNMP_ERR_NOERROR;
00511                     }
00512                 }
00513             }
00514 
00515             /* if sorted, pass in a hint */
00516             if (iinfo->flags & NETSNMP_ITERATOR_FLAG_SORTED) {
00517                 callback_loop_context = table_info;
00518             }
00519             index_search =
00520                 (iinfo->get_first_data_point) (&callback_loop_context,
00521                                                &callback_data_context,
00522                                                index_search, iinfo);
00523 
00524             /* loop over each data point */
00525             while(index_search) {
00526 
00527                 /* remember to free this later */
00528                 free_this_index_search = index_search;
00529             
00530                 /* compare against each request*/
00531                 for(request = requests ; request; request = request->next) {
00532                     if (request->processed)
00533                         continue;
00534 
00535                     /* XXX: store in an array for faster retrival */
00536                     table_info = netsnmp_extract_table_info(request);
00537                     coloid[reginfo->rootoid_len + 1] = table_info->colnum;
00538 
00539                     ti_info =
00540                         netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
00541 
00542                     switch(reqinfo->mode) {
00543                     case MODE_GET:
00544                     case MODE_SET_RESERVE1:
00545                         /* looking for exact matches */
00546                         build_oid_noalloc(myname, MAX_OID_LEN, &myname_len,
00547                                           coloid, coloid_len, index_search);
00548                         if (snmp_oid_compare(myname, myname_len,
00549                                              request->requestvb->name,
00550                                              request->requestvb->name_length) == 0) {
00551                             /* keep this */
00552                             netsnmp_iterator_remember(request,
00553                                                       myname, myname_len,
00554                                                       callback_data_context,
00555                                                       callback_loop_context, iinfo);
00556                             request_count--;   /* One less to look for */
00557                         } else {
00558                             if (iinfo->free_data_context && callback_data_context) {
00559                                 (iinfo->free_data_context)(callback_data_context,
00560                                                            iinfo);
00561                             }
00562                         }
00563                         break;
00564 
00565                     case MODE_GET_STASH:
00566                         /* collect data for each column for every row */
00567                         build_oid_noalloc(myname, MAX_OID_LEN, &myname_len,
00568                                           coloid, coloid_len, index_search);
00569                         reqinfo->mode = MODE_GET;
00570                         ldata =
00571                             netsnmp_get_list_node(reqtmp->parent_data,
00572                                                   TABLE_ITERATOR_NAME);
00573                         if (!ldata) {
00574                             netsnmp_request_add_list_data(reqtmp,
00575                                                           netsnmp_create_data_list
00576                                                           (TABLE_ITERATOR_NAME,
00577                                                            callback_data_context,
00578                                                            NULL));
00579                         } else {
00580                             /* may have changed */
00581                             ldata->data = callback_data_context;
00582                         }
00583 
00584                         table_info->indexes = index_search;
00585                         for(i = table_reg_info->min_column;
00586                             i <= (int)table_reg_info->max_column; i++) {
00587                             myname[reginfo->rootoid_len + 1] = i;
00588                             table_info->colnum = i;
00589                             vb = reqtmp->requestvb =
00590                                 SNMP_MALLOC_TYPEDEF(netsnmp_variable_list);
00591                             vb->type = ASN_NULL;
00592                             snmp_set_var_objid(vb, myname, myname_len);
00593                             netsnmp_call_next_handler(handler, reginfo,
00594                                                       reqinfo, reqtmp);
00595                             reqtmp->requestvb = NULL;
00596                             reqtmp->processed = 0;
00597                             if (vb->type != ASN_NULL) { /* XXX, not all */
00598                                 netsnmp_oid_stash_add_data(cinfo, myname,
00599                                                            myname_len, vb);
00600                             } else {
00601                                 snmp_free_var(vb);
00602                             }
00603                         }
00604                         reqinfo->mode = MODE_GET_STASH;
00605                         break;
00606 
00607                     case MODE_GETNEXT:
00608                         /* looking for "next" matches */
00609                         if (netsnmp_check_getnext_reply
00610                             (request, coloid, coloid_len, index_search,
00611                              &ti_info->results)) {
00612                             netsnmp_iterator_remember(request,
00613                                                       ti_info->results->name,
00614                                                       ti_info->results->name_length,
00615                                                       callback_data_context,
00616                                                       callback_loop_context, iinfo);
00617                             /*
00618                              *  If we've been told that the rows are sorted,
00619                              *   then the first valid one we find
00620                              *   must be the right one.
00621                              */
00622                             if (iinfo->flags & NETSNMP_ITERATOR_FLAG_SORTED)
00623                                 request_count--;
00624                         
00625                         } else {
00626                             if (iinfo->free_data_context && callback_data_context) {
00627                                 (iinfo->free_data_context)(callback_data_context,
00628                                                            iinfo);
00629                             }
00630                         }
00631                         break;
00632 
00633                     case MODE_SET_RESERVE2:
00634                     case MODE_SET_FREE:
00635                     case MODE_SET_UNDO:
00636                     case MODE_SET_COMMIT:
00637                         /* needed processing already done in RESERVE1 */
00638                         break;
00639 
00640                     default:
00641                         snmp_log(LOG_ERR,
00642                                  "table_iterator called with unsupported mode\n");
00643                         break;  /* XXX return */
00644                 
00645                     }
00646                 }
00647 
00648                 /* Is there any point in carrying on? */
00649                 if (!request_count)
00650                     break;
00651                 /* get the next search possibility */
00652                 last_loop_context = callback_loop_context;
00653                 index_search =
00654                     (iinfo->get_next_data_point) (&callback_loop_context,
00655                                                   &callback_data_context,
00656                                                   index_search, iinfo);
00657                 if (iinfo->free_loop_context && last_loop_context &&
00658                     callback_data_context != last_loop_context) {
00659                     (iinfo->free_loop_context) (last_loop_context, iinfo);
00660                     last_loop_context = NULL;
00661                 }
00662             }
00663 
00664             /* free loop context before going on */
00665             if (callback_loop_context && iinfo->free_loop_context_at_end) {
00666                 (iinfo->free_loop_context_at_end) (callback_loop_context,
00667                                                    iinfo);
00668                 callback_loop_context = NULL;
00669             }
00670 
00671             /* decide which (GETNEXT) requests are not yet filled */
00672             if (reqinfo->mode == MODE_GETNEXT) {
00673                 for(request = requests ; request; request = request->next) {
00674                     if (request->processed)
00675                         continue;
00676                     ti_info =
00677                         netsnmp_request_get_list_data(request,
00678                                                       TI_REQUEST_CACHE);
00679                     if (!ti_info->results) {
00680                         table_info = netsnmp_extract_table_info(request);
00681                         table_info->colnum =
00682                             netsnmp_table_next_column(table_info);
00683                         if (0 == table_info->colnum) {
00684                             coloid[reginfo->rootoid_len+1] = table_info->colnum+1;
00685                             snmp_set_var_objid(request->requestvb,
00686                                                coloid, reginfo->rootoid_len+2);
00687                             request->processed = TABLE_ITERATOR_NOTAGAIN;
00688                             break;
00689                         } else {
00690                             notdone = 1;
00691                         }
00692                     }
00693                 }
00694             }
00695         }
00696     }
00697 
00698     if (reqinfo->mode == MODE_GET ||
00699         reqinfo->mode == MODE_GETNEXT ||
00700         reqinfo->mode == MODE_SET_RESERVE1) {
00701         /* per request last minute processing */
00702         for(request = requests ; request; request = request->next) {
00703             if (request->processed)
00704                 continue;
00705             ti_info =
00706                 netsnmp_request_get_list_data(request, TI_REQUEST_CACHE);
00707             table_info =
00708                 netsnmp_extract_table_info(request);
00709 
00710             if (!ti_info)
00711                 continue;
00712         
00713             switch(reqinfo->mode) {
00714 
00715             case MODE_GETNEXT:
00716                 if (ti_info->best_match_len)
00717                     snmp_set_var_objid(request->requestvb, ti_info->best_match,
00718                                        ti_info->best_match_len);
00719                 else {
00720                     coloid[reginfo->rootoid_len+1] = 
00721                         netsnmp_table_next_column(table_info);
00722                     if (0 == coloid[reginfo->rootoid_len+1]) {
00723                         /* out of range. */
00724                         coloid[reginfo->rootoid_len+1] = tbl_info->max_column + 1;
00725                         request->processed = TABLE_ITERATOR_NOTAGAIN;
00726                     }
00727                     snmp_set_var_objid(request->requestvb,
00728                                        coloid, reginfo->rootoid_len+2);
00729                     request->processed = 1;
00730                 }
00731                 snmp_free_varbind(table_info->indexes);
00732                 table_info->indexes = snmp_clone_varbind(ti_info->results);
00733                 /* FALL THROUGH */
00734 
00735             case MODE_GET:
00736             case MODE_SET_RESERVE1:
00737                 if (ti_info->data_context)
00738                     /* we don't add a free pointer, since it's in the
00739                        TI_REQUEST_CACHE instead */
00740                     netsnmp_request_add_list_data(request,
00741                                                   netsnmp_create_data_list
00742                                                   (TABLE_ITERATOR_NAME,
00743                                                    ti_info->data_context,
00744                                                    NULL));
00745                 break;
00746             
00747             default:
00748                 break;
00749             }
00750         }
00751             
00752         /* we change all GETNEXT operations into GET operations.
00753            why? because we're just so nice to the lower levels.
00754            maybe someday they'll pay us for it.  doubtful though. */
00755         oldmode = reqinfo->mode;
00756         if (reqinfo->mode == MODE_GETNEXT) {
00757             reqinfo->mode = MODE_GET;
00758         }
00759     } else if (reqinfo->mode == MODE_GET_STASH) {
00760         netsnmp_free_request_data_sets(reqtmp);
00761         SNMP_FREE(reqtmp);
00762         table_info->indexes = old_indexes;
00763     }
00764 
00765 
00766     /* Finally, we get to call the next handler below us.  Boy, wasn't
00767        all that simple?  They better be glad they don't have to do it! */
00768     if (reqinfo->mode != MODE_GET_STASH) {
00769         DEBUGMSGTL(("table_iterator", "call subhandler for mode: %s\n",
00770                     se_find_label_in_slist("agent_mode", oldmode)));
00771         ret =
00772             netsnmp_call_next_handler(handler, reginfo, reqinfo, requests);
00773     }
00774 
00775     /* reverse the previously saved mode if we were a getnext */
00776     if (oldmode == MODE_GETNEXT) {
00777         reqinfo->mode = oldmode;
00778     }
00779 
00780     /* cleanup */
00781     if (free_this_index_search)
00782         snmp_free_varbind(free_this_index_search);
00783 
00784     return SNMP_ERR_NOERROR;
00785 }
00786 
00787 /* ==================================
00788  *
00789  * Iterator API: Row operations
00790  *
00791  * ================================== */
00792 
00793 void *
00794 netsnmp_iterator_row_first( netsnmp_iterator_info *iinfo ) {
00795     netsnmp_variable_list *vp1, *vp2;
00796     void *ctx1, *ctx2;
00797 
00798     if (!iinfo)
00799         return NULL;
00800 
00801     vp1 = snmp_clone_varbind(iinfo->indexes);
00802     vp2 = iinfo->get_first_data_point( &ctx1, &ctx2, vp1, iinfo );
00803 
00804     if (!vp2)
00805         ctx2 = NULL;
00806 
00807     /* free loop context ?? */
00808     snmp_free_varbind( vp1 );
00809     return ctx2;  /* or *ctx2 ?? */
00810 }
00811 
00812 void *
00813 netsnmp_iterator_row_get( netsnmp_iterator_info *iinfo, void *row )
00814 {
00815     netsnmp_variable_list *vp1, *vp2;
00816     void *ctx1, *ctx2;
00817 
00818     if (!iinfo || !row)
00819         return NULL;
00820 
00821         /*
00822          * This routine relies on being able to
00823          *   determine the indexes for a given row.  
00824          */
00825     if (!iinfo->get_row_indexes)
00826         return NULL;
00827 
00828     vp1  = snmp_clone_varbind(iinfo->indexes);
00829     ctx1 = row;   /* Probably only need one of these ... */
00830     ctx2 = row;
00831     vp2  = iinfo->get_row_indexes( &ctx1, &ctx2, vp1, iinfo );
00832 
00833     ctx2 = NULL;
00834     if (vp2) {
00835         ctx2 = netsnmp_iterator_row_get_byidx( iinfo, vp2 );
00836     }
00837     snmp_free_varbind( vp1 );
00838     return ctx2;
00839 }
00840 
00841 void *
00842 netsnmp_iterator_row_next( netsnmp_iterator_info *iinfo, void *row )
00843 {
00844     netsnmp_variable_list *vp1, *vp2;
00845     void *ctx1, *ctx2;
00846 
00847     if (!iinfo || !row)
00848         return NULL;
00849 
00850         /*
00851          * This routine relies on being able to
00852          *   determine the indexes for a given row.  
00853          */
00854     if (!iinfo->get_row_indexes)
00855         return NULL;
00856 
00857     vp1  = snmp_clone_varbind(iinfo->indexes);
00858     ctx1 = row;   /* Probably only need one of these ... */
00859     ctx2 = row;
00860     vp2  = iinfo->get_row_indexes( &ctx1, &ctx2, vp1, iinfo );
00861 
00862     ctx2 = NULL;
00863     if (vp2) {
00864         ctx2 = netsnmp_iterator_row_next_byidx( iinfo, vp2 );
00865     }
00866     snmp_free_varbind( vp1 );
00867     return ctx2;
00868 }
00869 
00870 void *
00871 netsnmp_iterator_row_get_byidx(  netsnmp_iterator_info *iinfo,
00872                                  netsnmp_variable_list *indexes )
00873 {
00874     oid    dummy[] = {0,0};   /* Keep 'build_oid' happy */
00875     oid    instance[MAX_OID_LEN];
00876     size_t len =    MAX_OID_LEN;
00877 
00878     if (!iinfo || !indexes)
00879         return NULL;
00880 
00881     build_oid_noalloc(instance, MAX_OID_LEN, &len,
00882                       dummy, 2, indexes);
00883     return netsnmp_iterator_row_get_byoid( iinfo, instance+2, len-2 );
00884 }
00885 
00886 void *
00887 netsnmp_iterator_row_next_byidx( netsnmp_iterator_info *iinfo,
00888                                  netsnmp_variable_list *indexes )
00889 {
00890     oid    dummy[] = {0,0};
00891     oid    instance[MAX_OID_LEN];
00892     size_t len =    MAX_OID_LEN;
00893 
00894     if (!iinfo || !indexes)
00895         return NULL;
00896 
00897     build_oid_noalloc(instance, MAX_OID_LEN, &len,
00898                       dummy, 2, indexes);
00899     return netsnmp_iterator_row_next_byoid( iinfo, instance+2, len-2 );
00900 }
00901 
00902 void *
00903 netsnmp_iterator_row_get_byoid(  netsnmp_iterator_info *iinfo,
00904                                  oid *instance, size_t len )
00905 {
00906     oid    dummy[] = {0,0};
00907     oid    this_inst[ MAX_OID_LEN];
00908     size_t this_len;
00909     netsnmp_variable_list *vp1, *vp2;
00910     void *ctx1, *ctx2;
00911     int   n;
00912 
00913     if (!iinfo || !iinfo->get_first_data_point
00914                || !iinfo->get_next_data_point )
00915         return NULL;
00916 
00917     if ( !instance || !len )
00918         return NULL;
00919 
00920     vp1 = snmp_clone_varbind(iinfo->indexes);
00921     vp2 = iinfo->get_first_data_point( &ctx1, &ctx2, vp1, iinfo );
00922     DEBUGMSGTL(("table:iterator:get", "first DP: %x %x %x\n",
00923                                        ctx1, ctx2, vp2));
00924 
00925     /* XXX - free context ? */
00926     
00927     while ( vp2 ) {
00928         this_len = MAX_OID_LEN;
00929         build_oid_noalloc(this_inst, MAX_OID_LEN, &this_len, dummy, 2, vp2);
00930         n = snmp_oid_compare( instance, len, this_inst+2, this_len-2 );
00931         if ( n == 0 )
00932             break;  /* Found matching row */
00933 
00934         if (( n > 0) &&
00935             (iinfo->flags & NETSNMP_ITERATOR_FLAG_SORTED)) {
00936             vp2 = NULL;  /* Row not present */
00937             break;
00938         }
00939         
00940         vp2 = iinfo->get_next_data_point( &ctx1, &ctx2, vp2, iinfo );
00941         DEBUGMSGTL(("table:iterator:get", "next DP: %x %x %x\n",
00942                                            ctx1, ctx2, vp2));
00943         /* XXX - free context ? */
00944     }
00945            
00946     /* XXX - final free context ? */
00947     snmp_free_varbind( vp1 );
00948 
00949     return ( vp2 ? ctx2 : NULL );
00950 }
00951 
00952 void *
00953 netsnmp_iterator_row_next_byoid( netsnmp_iterator_info *iinfo,
00954                                  oid *instance, size_t len )
00955 {
00956     oid    dummy[] = {0,0};
00957     oid    this_inst[ MAX_OID_LEN];
00958     size_t this_len;
00959     oid    best_inst[ MAX_OID_LEN];
00960     size_t best_len = 0;
00961     netsnmp_variable_list *vp1, *vp2;
00962     void *ctx1, *ctx2;
00963     int   n;
00964 
00965     if (!iinfo || !iinfo->get_first_data_point
00966                || !iinfo->get_next_data_point )
00967         return NULL;
00968 
00969     vp1 = snmp_clone_varbind(iinfo->indexes);
00970     vp2 = iinfo->get_first_data_point( &ctx1, &ctx2, vp1, iinfo );
00971     DEBUGMSGTL(("table:iterator:get", "first DP: %x %x %x\n",
00972                                        ctx1, ctx2, vp2));
00973 
00974     if ( !instance || !len ) {
00975         snmp_free_varbind( vp1 );
00976         return ( vp2 ? ctx2 : NULL );   /* First entry */
00977     }
00978 
00979     /* XXX - free context ? */
00980     
00981     while ( vp2 ) {
00982         this_len = MAX_OID_LEN;
00983         build_oid_noalloc(this_inst, MAX_OID_LEN, &this_len, dummy, 2, vp2);
00984         n = snmp_oid_compare( instance, len, this_inst+2, this_len-2 );
00985 
00986         /*
00987          * Look for the best-fit candidate for the next row
00988          *   (bearing in mind the rows may not be ordered "correctly")
00989          */
00990         if ( n > 0 ) {
00991             if ( best_len == 0 ) {
00992                 memcpy( best_inst, this_inst, sizeof( this_inst ));
00993                 best_len = this_len;
00994                 if (iinfo->flags & NETSNMP_ITERATOR_FLAG_SORTED)
00995                     break;
00996             } else {
00997                 n = snmp_oid_compare( best_inst, best_len, this_inst, this_len );
00998                 if ( n < 0 ) {
00999                     memcpy( best_inst, this_inst, sizeof( this_inst ));
01000                     best_len = this_len;
01001                     if (iinfo->flags & NETSNMP_ITERATOR_FLAG_SORTED)
01002                         break;
01003                 }
01004             }
01005         }
01006         
01007         vp2 = iinfo->get_next_data_point( &ctx1, &ctx2, vp2, iinfo );
01008         DEBUGMSGTL(("table:iterator:get", "next DP: %x %x %x\n",
01009                                            ctx1, ctx2, vp2));
01010         /* XXX - free context ? */
01011     }
01012            
01013     /* XXX - final free context ? */
01014     snmp_free_varbind( vp1 );
01015 
01016     return ( vp2 ? ctx2 : NULL );
01017 }
01018 
01019 int
01020 netsnmp_iterator_row_count( netsnmp_iterator_info *iinfo )
01021 {
01022     netsnmp_variable_list *vp1, *vp2;
01023     void *ctx1, *ctx2;
01024     int   i=0;
01025 
01026     if (!iinfo || !iinfo->get_first_data_point
01027                || !iinfo->get_next_data_point )
01028         return 0;
01029 
01030     vp1 = snmp_clone_varbind(iinfo->indexes);
01031     vp2 = iinfo->get_first_data_point( &ctx1, &ctx2, vp1, iinfo );
01032     if (!vp2) {
01033         snmp_free_varbind( vp1 );
01034         return 0;
01035     }
01036     
01037     DEBUGMSGTL(("table:iterator:count", "first DP: %x %x %x\n",
01038                                          ctx1, ctx2, vp2));
01039 
01040     /* XXX - free context ? */
01041 
01042     while (vp2) {
01043         i++;
01044         vp2 = iinfo->get_next_data_point( &ctx1, &ctx2, vp2, iinfo );
01045         DEBUGMSGTL(("table:iterator:count", "next DP: %x %x %x (%d)\n",
01046                                              ctx1, ctx2, vp2, i));
01047         /* XXX - free context ? */
01048     }
01049            
01050     /* XXX - final free context ? */
01051     snmp_free_varbind( vp1 );
01052     return i;
01053 }
01054 
01055 
01056 /* ==================================
01057  *
01058  * Iterator API: Index operations
01059  *
01060  * ================================== */
01061 
01062 

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

Valid CSS!


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