00001
00002
00003
00004
00005
00006 #include <net-snmp/net-snmp-config.h>
00007
00008 #include <stdio.h>
00009 #if HAVE_STDLIB_H
00010 #include <stdlib.h>
00011 #endif
00012 #if HAVE_MALLOC_H
00013 #include <malloc.h>
00014 #endif
00015 #include <sys/types.h>
00016 #if HAVE_STRING_H
00017 #include <string.h>
00018 #else
00019 #include <strings.h>
00020 #endif
00021
00022 #include <net-snmp/net-snmp-includes.h>
00023 #include <net-snmp/types.h>
00024 #include <net-snmp/library/snmp_api.h>
00025 #include <net-snmp/library/container.h>
00026 #include <net-snmp/library/tools.h>
00027 #include <net-snmp/library/snmp_assert.h>
00028
00029 #include <net-snmp/library/container_iterator.h>
00030
00043 typedef struct iterator_info_s {
00044
00045
00046
00047 netsnmp_container c;
00048
00049
00050
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
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
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
00116
00117
00118 if((cmp > 0) && ii->sorted)
00119 break;
00120 }
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
00149
00150 if(ii->init_loop_ctx)
00151 ii->init_loop_ctx(ii->user_ctx, &loop_ctx);
00152
00153
00154
00155
00156 rc = ii->get_first(ii->user_ctx, &loop_ctx, &tmp);
00157 if(SNMP_ERR_NOERROR == rc) {
00158
00159
00160
00161
00162
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;
00170 else
00171 rc = ii->get_next(ii->user_ctx, &loop_ctx, &tmp);
00172 }
00173
00174
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
00182
00183
00184
00185
00186
00187
00188
00189 if(key)
00190 cmp = ii->c.compare(tmp.val, key);
00191 else {
00192
00193
00194
00195
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
00208
00209
00210
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
00223
00224
00225
00226
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;
00236 break;
00237 }
00238
00239 }
00240 }
00241
00242
00243
00244
00245 if(SNMP_ENDOFMIBVIEW == rc)
00246 rc = SNMP_ERR_NOERROR;
00247
00248
00249
00250
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
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
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
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
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
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
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
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
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 }