net-snmp 5.7
|
00001 /* 00002 * $Id$ 00003 * 00004 */ 00005 00006 #include <net-snmp/net-snmp-config.h> 00007 #include <net-snmp/net-snmp-features.h> 00008 00009 #include <stdio.h> 00010 #if HAVE_STDLIB_H 00011 #include <stdlib.h> 00012 #endif 00013 #if HAVE_MALLOC_H 00014 #include <malloc.h> 00015 #endif 00016 #include <sys/types.h> 00017 #if HAVE_STRING_H 00018 #include <string.h> 00019 #else 00020 #include <strings.h> 00021 #endif 00022 00023 #include <net-snmp/net-snmp-includes.h> 00024 #include <net-snmp/types.h> 00025 #include <net-snmp/library/snmp_api.h> 00026 #include <net-snmp/library/container.h> 00027 #include <net-snmp/library/tools.h> 00028 #include <net-snmp/library/snmp_assert.h> 00029 00030 #include <net-snmp/library/container_iterator.h> 00031 00032 netsnmp_feature_child_of(container_iterator, container_types) 00033 00034 #ifndef NETSNMP_FEATURE_REMOVE_CONTAINER_ITERATOR 00035 00043 typedef struct iterator_info_s { 00044 /* 00045 * netsnmp_conatiner must be first 00046 */ 00047 netsnmp_container c; 00048 00049 /* 00050 * iterator data 00051 */ 00052 Netsnmp_Iterator_Loop_Key *get_first; 00053 Netsnmp_Iterator_Loop_Key *get_next; 00054 00055 Netsnmp_Iterator_Loop_Data *get_data; 00056 00057 Netsnmp_Iterator_Data *free_user_ctx; 00058 00059 Netsnmp_Iterator_Ctx *init_loop_ctx; 00060 Netsnmp_Iterator_Ctx *cleanup_loop_ctx; 00061 Netsnmp_Iterator_Ctx_Dup *save_pos; 00062 00063 Netsnmp_Iterator_Data * release_data; 00064 Netsnmp_Iterator_Data * insert_data; 00065 Netsnmp_Iterator_Data * remove_data; 00066 00067 Netsnmp_Iterator_Op * get_size; 00068 00069 int sorted; 00070 00073 void *user_ctx; 00074 } iterator_info; 00075 00076 /********************************************************************** 00077 * 00078 * iterator 00079 * 00080 **********************************************************************/ 00081 static void * 00082 _iterator_get(iterator_info *ii, const void *key) 00083 { 00084 int cmp, rc = SNMP_ERR_NOERROR; 00085 netsnmp_ref_void best = { NULL }; 00086 netsnmp_ref_void tmp = { NULL }; 00087 netsnmp_ref_void loop_ctx = { NULL }; 00088 00089 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get")); 00090 00091 if(ii->init_loop_ctx) 00092 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00093 00094 rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00095 if(SNMP_ERR_NOERROR != rc) { 00096 if(SNMP_ENDOFMIBVIEW != rc) 00097 snmp_log(LOG_ERR, "bad rc %d from get_next\n", rc); 00098 } 00099 else { 00100 for( ; 00101 (NULL != tmp.val) && (SNMP_ERR_NOERROR == rc); 00102 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) { 00103 00104 /* 00105 * if keys are equal, we are done. 00106 */ 00107 cmp = ii->c.compare(tmp.val, key); 00108 if(0 == cmp) { 00109 best.val = tmp.val; 00110 if(ii->get_data) 00111 ii->get_data(ii->user_ctx, &loop_ctx, &best); 00112 } 00113 00114 /* 00115 * if data is sorted and if key is greater, 00116 * we are done (not found) 00117 */ 00118 if((cmp > 0) && ii->sorted) 00119 break; 00120 } /* end for */ 00121 } 00122 00123 if(ii->cleanup_loop_ctx) 00124 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00125 00126 return best.val; 00127 } 00128 00136 static void * 00137 _iterator_get_next(iterator_info *ii, const void *key) 00138 { 00139 int cmp, rc = SNMP_ERR_NOERROR; 00140 netsnmp_ref_void best_val = { NULL }; 00141 netsnmp_ref_void best_ctx = { NULL }; 00142 netsnmp_ref_void tmp = { NULL }; 00143 netsnmp_ref_void loop_ctx = { NULL }; 00144 00145 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_get_next")); 00146 00147 /* 00148 * initialize loop context 00149 */ 00150 if(ii->init_loop_ctx) 00151 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00152 00153 /* 00154 * get first item 00155 */ 00156 rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00157 if(SNMP_ERR_NOERROR == rc) { 00158 /* 00159 * special case: if key is null, find the first item. 00160 * this is each if the container is sorted, since we're 00161 * already done! Otherwise, get the next item for the 00162 * first comparison in the loop below. 00163 */ 00164 if (NULL == key) { 00165 if(ii->get_data) 00166 ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1); 00167 best_val.val = tmp.val; 00168 if(ii->sorted) 00169 tmp.val = NULL; /* so we skip for loop */ 00170 else 00171 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp); 00172 } 00173 /* 00174 * loop over remaining items 00175 */ 00176 for( ; 00177 (NULL != tmp.val) && (rc == SNMP_ERR_NOERROR); 00178 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) { 00179 00180 /* 00181 * if we have a key, this is a get-next, and we need to compare 00182 * the key to the tmp value to see if the tmp value is greater 00183 * than the key, but less than any previous match. 00184 * 00185 * if there is no key, this is a get-first, and we need to 00186 * compare the best value agains the tmp value to see if the 00187 * tmp value is lesser than the best match. 00188 */ 00189 if(key) /* get next */ 00190 cmp = ii->c.compare(tmp.val, key); 00191 else { /* get first */ 00192 /* 00193 * best value and tmp value should never be equal, 00194 * otherwise we'd be comparing a pointer to itself. 00195 * (see note on context reuse in comments above function. 00196 */ 00197 if(best_val.val == tmp.val) { 00198 snmp_log(LOG_ERR,"illegal reuse of data context in " 00199 "container_iterator\n"); 00200 rc = SNMP_ERR_GENERR; 00201 break; 00202 } 00203 cmp = ii->c.compare(best_val.val, tmp.val); 00204 } 00205 if(cmp > 0) { 00206 /* 00207 * if we don't have a key (get-first) or a current best match, 00208 * then the comparison above is all we need to know that 00209 * tmp is the best match. otherwise, compare against the 00210 * current best match. 00211 */ 00212 if((NULL == key) || (NULL == best_val.val) || 00213 ((cmp=ii->c.compare(tmp.val, best_val.val)) < 0) ) { 00214 DEBUGMSGT(("container_iterator:results"," best match\n")); 00215 best_val.val = tmp.val; 00216 if(ii->get_data) 00217 ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1); 00218 } 00219 } 00220 else if((cmp == 0) && ii->sorted && key) { 00221 /* 00222 * if keys are equal and container is sorted, then we know 00223 * the next key will be the one we want. 00224 * NOTE: if no vars, treat as generr, since we 00225 * went past the end of the container when we know 00226 * the next item is the one we want. (IGN-A) 00227 */ 00228 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp); 00229 if(SNMP_ERR_NOERROR == rc) { 00230 best_val.val = tmp.val; 00231 if(ii->get_data) 00232 ii->save_pos(ii->user_ctx, &loop_ctx, &best_ctx, 1); 00233 } 00234 else if(SNMP_ENDOFMIBVIEW == rc) 00235 rc = SNMPERR_GENERR; /* not found */ 00236 break; 00237 } 00238 00239 } /* end for */ 00240 } 00241 00242 /* 00243 * no vars is ok, except as noted above (IGN-A) 00244 */ 00245 if(SNMP_ENDOFMIBVIEW == rc) 00246 rc = SNMP_ERR_NOERROR; 00247 00248 /* 00249 * get data, iff necessary 00250 * clear return value iff errors 00251 */ 00252 if(SNMP_ERR_NOERROR == rc) { 00253 if(ii->get_data && best_val.val) { 00254 rc = ii->get_data(ii->user_ctx, &best_ctx, &best_val); 00255 if(SNMP_ERR_NOERROR != rc) { 00256 snmp_log(LOG_ERR, "bad rc %d from get_data\n", rc); 00257 best_val.val = NULL; 00258 } 00259 } 00260 } 00261 else if(SNMP_ENDOFMIBVIEW != rc) { 00262 snmp_log(LOG_ERR, "bad rc %d from get_next\n", rc); 00263 best_val.val = NULL; 00264 } 00265 00266 /* 00267 * if we have a saved loop ctx, clean it up 00268 */ 00269 if((best_ctx.val != NULL) && (best_ctx.val != loop_ctx.val) && 00270 (ii->cleanup_loop_ctx)) 00271 ii->cleanup_loop_ctx(ii->user_ctx,&best_ctx); 00272 00273 /* 00274 * clean up loop ctx 00275 */ 00276 if(ii->cleanup_loop_ctx) 00277 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00278 00279 DEBUGMSGT(("container_iterator:results"," returning %p\n", best_val.val)); 00280 return best_val.val; 00281 } 00282 00283 /********************************************************************** 00284 * 00285 * container 00286 * 00287 **********************************************************************/ 00288 static void 00289 _iterator_free(iterator_info *ii) 00290 { 00291 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_free")); 00292 00293 if(NULL == ii) 00294 return; 00295 00296 if(ii->user_ctx) 00297 ii->free_user_ctx(ii->user_ctx,ii->user_ctx); 00298 00299 free(ii); 00300 } 00301 00302 static void * 00303 _iterator_find(iterator_info *ii, const void *data) 00304 { 00305 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find")); 00306 00307 if((NULL == ii) || (NULL == data)) 00308 return NULL; 00309 00310 return _iterator_get(ii, data); 00311 } 00312 00313 static void * 00314 _iterator_find_next(iterator_info *ii, const void *data) 00315 { 00316 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_find_next")); 00317 00318 if(NULL == ii) 00319 return NULL; 00320 00321 return _iterator_get_next(ii, data); 00322 } 00323 00324 static int 00325 _iterator_insert(iterator_info *ii, const void *data) 00326 { 00327 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_insert")); 00328 00329 if(NULL == ii) 00330 return -1; 00331 00332 if(NULL == ii->insert_data) 00333 return -1; 00334 00335 return ii->insert_data(ii->user_ctx, data); 00336 } 00337 00338 static int 00339 _iterator_remove(iterator_info *ii, const void *data) 00340 { 00341 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_remove")); 00342 00343 if(NULL == ii) 00344 return -1; 00345 00346 if(NULL == ii->remove_data) 00347 return -1; 00348 00349 return ii->remove_data(ii->user_ctx, data); 00350 } 00351 00352 static int 00353 _iterator_release(iterator_info *ii, const void *data) 00354 { 00355 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_release")); 00356 00357 if(NULL == ii) 00358 return -1; 00359 00360 if(NULL == ii->release_data) 00361 return -1; 00362 00363 return ii->release_data(ii->user_ctx, data); 00364 } 00365 00366 static size_t 00367 _iterator_size(iterator_info *ii) 00368 { 00369 size_t count = 0; 00370 int rc = SNMP_ERR_NOERROR; 00371 netsnmp_ref_void loop_ctx = { NULL }; 00372 netsnmp_ref_void tmp = { NULL }; 00373 00374 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_size")); 00375 00376 if(NULL == ii) 00377 return -1; 00378 00379 if(NULL != ii->get_size) 00380 return ii->get_size(ii->user_ctx); 00381 00382 /* 00383 * no get_size. loop and count ourselves 00384 */ 00385 if(ii->init_loop_ctx) 00386 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00387 00388 for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00389 NULL != tmp.val; 00390 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) 00391 ++count; 00392 00393 if(ii->cleanup_loop_ctx) 00394 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00395 00396 return count; 00397 } 00398 00399 static void 00400 _iterator_for_each(iterator_info *ii, netsnmp_container_obj_func *f, 00401 void *ctx) 00402 { 00403 int rc = SNMP_ERR_NOERROR; 00404 netsnmp_ref_void loop_ctx = { NULL }; 00405 netsnmp_ref_void tmp = { NULL }; 00406 00407 DEBUGMSGT(("container_iterator",">%s\n", "_iterator_foreach")); 00408 00409 if(NULL == ii) 00410 return; 00411 00412 if(ii->init_loop_ctx) 00413 ii->init_loop_ctx(ii->user_ctx, &loop_ctx); 00414 00415 for( rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp); 00416 NULL != tmp.val; 00417 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp) ) 00418 (*f) (tmp.val, ctx); 00419 00420 if(ii->cleanup_loop_ctx) 00421 ii->cleanup_loop_ctx(ii->user_ctx,&loop_ctx); 00422 } 00423 00424 static void 00425 _iterator_clear(netsnmp_container *container, netsnmp_container_obj_func *f, 00426 void *context) 00427 { 00428 snmp_log(LOG_WARNING,"clear is meaningless for iterator container.\n"); 00429 } 00430 00431 /********************************************************************** 00432 * 00433 */ 00434 netsnmp_container* 00435 netsnmp_container_iterator_get(void *iterator_user_ctx, 00436 netsnmp_container_compare * compare, 00437 Netsnmp_Iterator_Loop_Key * get_first, 00438 Netsnmp_Iterator_Loop_Key * get_next, 00439 Netsnmp_Iterator_Loop_Data * get_data, 00440 Netsnmp_Iterator_Ctx_Dup * save_pos, 00441 Netsnmp_Iterator_Ctx * init_loop_ctx, 00442 Netsnmp_Iterator_Ctx * cleanup_loop_ctx, 00443 Netsnmp_Iterator_Data * free_user_ctx, 00444 int sorted) 00445 { 00446 iterator_info *ii; 00447 00448 /* 00449 * sanity checks 00450 */ 00451 if(get_data && ! save_pos) { 00452 snmp_log(LOG_ERR, "save_pos required with get_data\n"); 00453 return NULL; 00454 } 00455 00456 /* 00457 * allocate memory 00458 */ 00459 ii = SNMP_MALLOC_TYPEDEF(iterator_info); 00460 if (NULL==ii) { 00461 snmp_log(LOG_ERR, "couldn't allocate memory\n"); 00462 return NULL; 00463 } 00464 00465 /* 00466 * init container structure with iterator functions 00467 */ 00468 ii->c.cfree = (netsnmp_container_rc*)_iterator_free; 00469 ii->c.compare = compare; 00470 ii->c.get_size = (netsnmp_container_size*)_iterator_size; 00471 ii->c.init = NULL; 00472 ii->c.insert = (netsnmp_container_op*)_iterator_insert; 00473 ii->c.remove = (netsnmp_container_op*)_iterator_remove; 00474 ii->c.release = (netsnmp_container_op*)_iterator_release; 00475 ii->c.find = (netsnmp_container_rtn*)_iterator_find; 00476 ii->c.find_next = (netsnmp_container_rtn*)_iterator_find_next; 00477 ii->c.get_subset = NULL; 00478 ii->c.get_iterator = NULL; 00479 ii->c.for_each = (netsnmp_container_func*)_iterator_for_each; 00480 ii->c.clear = _iterator_clear; 00481 00482 /* 00483 * init iterator structure with user functions 00484 */ 00485 ii->get_first = get_first; 00486 ii->get_next = get_next; 00487 ii->get_data = get_data; 00488 ii->save_pos = save_pos; 00489 ii->init_loop_ctx = init_loop_ctx; 00490 ii->cleanup_loop_ctx = cleanup_loop_ctx; 00491 ii->free_user_ctx = free_user_ctx; 00492 ii->sorted = sorted; 00493 00494 ii->user_ctx = iterator_user_ctx; 00495 00496 return (netsnmp_container*)ii; 00497 } 00498 00499 void 00500 netsnmp_container_iterator_set_data_cb(netsnmp_container *c, 00501 Netsnmp_Iterator_Data * insert_data, 00502 Netsnmp_Iterator_Data * remove_data, 00503 Netsnmp_Iterator_Op * get_size) 00504 { 00505 iterator_info *ii = (iterator_info *)c; 00506 if(NULL == ii) 00507 return; 00508 00509 ii->insert_data = insert_data; 00510 ii->remove_data = remove_data; 00511 ii->get_size = get_size; 00512 } 00513 #else /* NETSNMP_FEATURE_REMOVE_CONTAINER_ITERATOR */ 00514 netsnmp_feature_unused(container_iterator); 00515 #endif /* NETSNMP_FEATURE_REMOVE_CONTAINER_ITERATOR */