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
1.3.9.1
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.