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