00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include <net-snmp/net-snmp-config.h>
00019 #include <net-snmp/net-snmp-includes.h>
00020 #include <net-snmp/agent/net-snmp-agent-includes.h>
00021 #include <net-snmp/library/container.h>
00022 #include <net-snmp/library/snmp_assert.h>
00023
00024 #include "net-snmp/agent/object_monitor.h"
00025
00026 #if ! defined TRUE
00027 # define TRUE 1
00028 #elsif TRUE != 1
00029 error "TRUE != 1"
00030 #endif
00031
00032
00033
00034
00035
00036
00037
00038
00039 typedef struct monitor_info_s {
00040
00042 int priority;
00043
00045 netsnmp_mib_handler *watcher;
00046
00048 unsigned int events;
00049
00051 netsnmp_object_monitor_callback *cb;
00052
00054 void *watcher_data;
00055
00056 struct monitor_info_s *next;
00057
00058 } monitor_info;
00059
00060
00061
00062
00063 typedef struct watcher_list_s {
00064
00066 netsnmp_index monitored_object;
00067
00068 monitor_info *head;
00069
00070 } watcher_list;
00071
00072
00073
00074
00075 typedef struct callback_placeholder_s {
00076
00077 monitor_info *mi;
00078 netsnmp_monitor_callback_header *cbh;
00079
00080 struct callback_placeholder_s *next;
00081
00082 } callback_placeholder;
00083
00084
00085
00086
00087
00088
00089
00090
00091
00092
00093
00094 static char need_init = 1;
00095 static netsnmp_container *monitored_objects = NULL;
00096 static netsnmp_monitor_callback_header *callback_pending_list;
00097 static callback_placeholder *callback_ready_list;
00098
00099
00100
00101
00102 static watcher_list *find_watchers(oid * object, size_t oid_len);
00103 static int insert_watcher(oid *, size_t, monitor_info *);
00104 static int check_registered(unsigned int event, oid * o, int o_l,
00105 watcher_list ** pWl, monitor_info ** pMi);
00106 static void move_pending_to_ready(void);
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118 void
00119 netsnmp_monitor_init(void)
00120 {
00121 if (!need_init)
00122 return;
00123
00124 callback_pending_list = NULL;
00125 callback_ready_list = NULL;
00126
00127 monitored_objects = netsnmp_container_get("object_monitor:binary_array");
00128 if (NULL != monitored_objects)
00129 need_init = 0;
00130 monitored_objects->compare = netsnmp_compare_netsnmp_index;
00131 monitored_objects->ncompare = netsnmp_ncompare_netsnmp_index;
00132
00133 return;
00134 }
00135
00136
00137
00138
00139
00140
00141
00142
00168 int
00169 netsnmp_monitor_register(oid * object, size_t oid_len, int priority,
00170 unsigned int events, void *watcher_data,
00171 netsnmp_object_monitor_callback * cb)
00172 {
00173 monitor_info *mi;
00174 int rc;
00175
00176 netsnmp_assert(need_init == 0);
00177
00178 mi = calloc(1, sizeof(monitor_info));
00179 if (NULL == mi)
00180 return SNMPERR_MALLOC;
00181
00182 mi->priority = priority;
00183 mi->events = events;
00184 mi->watcher_data = watcher_data;
00185 mi->cb = cb;
00186
00187 rc = insert_watcher(object, oid_len, mi);
00188 if (rc != SNMPERR_SUCCESS)
00189 free(mi);
00190
00191 return rc;
00192 }
00193
00204 int
00205 netsnmp_monitor_unregister(oid * object, size_t oid_len, int priority,
00206 void *wd, netsnmp_object_monitor_callback * cb)
00207 {
00208 monitor_info *mi, *last;
00209
00210 watcher_list *wl = find_watchers(object, oid_len);
00211 if (NULL == wl)
00212 return SNMPERR_GENERR;
00213
00214 last = NULL;
00215 mi = wl->head;
00216 while (mi) {
00217 if ((mi->cb == cb) && (mi->priority == priority) &&
00218 (mi->watcher_data == wd))
00219 break;
00220 last = mi;
00221 mi = mi->next;
00222 }
00223
00224 if (NULL == mi)
00225 return SNMPERR_GENERR;
00226
00227 if (NULL == last)
00228 wl->head = mi->next;
00229 else
00230 last->next = mi->next;
00231
00232 if (NULL == wl->head) {
00233 CONTAINER_REMOVE(monitored_objects, wl);
00234 free(wl->monitored_object.oids);
00235 free(wl);
00236 }
00237
00238 free(mi);
00239
00240 return SNMPERR_SUCCESS;
00241 }
00242
00243
00244
00245
00246
00247
00248
00265 void
00266 netsnmp_notify_monitor(netsnmp_monitor_callback_header * cbh)
00267 {
00268
00269 netsnmp_assert(need_init == 0);
00270
00271
00272
00273
00274 cbh->private = callback_pending_list;
00275 callback_pending_list = cbh;
00276
00277 return;
00278 }
00279
00290 int
00291 netsnmp_monitor_check_registered(int event, oid * o, int o_l)
00292 {
00293 return check_registered(event, o, o_l, NULL, NULL);
00294 }
00295
00302 void
00303 netsnmp_monitor_process_callbacks(void)
00304 {
00305 netsnmp_assert(need_init == 0);
00306 netsnmp_assert(NULL == callback_ready_list);
00307
00308 if (NULL == callback_pending_list) {
00309 DEBUGMSGT(("object_monitor", "No callbacks to process"));
00310 return;
00311 }
00312
00313 DEBUGMSG(("object_monitor", "Checking for registered " "callbacks."));
00314
00315
00316
00317
00318
00319 move_pending_to_ready();
00320
00321
00322
00323
00324 while (callback_ready_list) {
00325
00326
00327
00328
00329 callback_placeholder *current_cbr;
00330 current_cbr = callback_ready_list;
00331 callback_ready_list = current_cbr->next;
00332
00333
00334
00335
00336 current_cbr->cbh->watcher_data = current_cbr->mi->watcher_data;
00337 current_cbr->cbh->priority = current_cbr->mi->priority;
00338 (*current_cbr->mi->cb) (current_cbr->cbh);
00339
00340
00341
00342
00343 if (--(current_cbr->cbh->refs) == 0) {
00344 free(current_cbr->cbh->monitored_object.oids);
00345 free(current_cbr->cbh);
00346 }
00347 free(current_cbr);
00348
00349
00350
00351
00352 move_pending_to_ready();
00353
00354 }
00355
00356 netsnmp_assert(callback_ready_list == NULL);
00357 netsnmp_assert(callback_pending_list = NULL);
00358
00359 return;
00360 }
00361
00362
00363
00364
00365
00366
00386 void
00387 netsnmp_notify_cooperative(int event, oid * o, size_t o_len, char o_steal,
00388 void *object_info)
00389 {
00390 netsnmp_monitor_callback_cooperative *cbh;
00391
00392 netsnmp_assert(need_init == 0);
00393
00394 cbh = SNMP_MALLOC_TYPEDEF(netsnmp_monitor_callback_cooperative);
00395 if (NULL == cbh) {
00396 snmp_log(LOG_ERR, "could not allocate memory for "
00397 "cooperative callback");
00398 return;
00399 }
00400
00401 cbh->hdr.event = event;
00402 cbh->hdr.object_info = object_info;
00403 cbh->hdr.monitored_object.len = o_len;
00404
00405 if (o_steal) {
00406 cbh->hdr.monitored_object.oids = o;
00407 } else {
00408 cbh->hdr.monitored_object.oids = snmp_duplicate_objid(o, o_len);
00409 }
00410
00411 netsnmp_notify_monitor((netsnmp_monitor_callback_header *) cbh);
00412 }
00413
00415
00416
00417
00418
00419
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430 static watcher_list *
00431 find_watchers(oid * object, size_t oid_len)
00432 {
00433 netsnmp_index oah;
00434
00435 oah.oids = object;
00436 oah.len = oid_len;
00437
00438 return (watcher_list *)CONTAINER_FIND(monitored_objects, &oah);
00439 }
00440
00441 static int
00442 insert_watcher(oid * object, size_t oid_len, monitor_info * mi)
00443 {
00444 watcher_list *wl = find_watchers(object, oid_len);
00445 int rc = SNMPERR_SUCCESS;
00446
00447 if (NULL != wl) {
00448
00449 monitor_info *last, *current;
00450
00451 netsnmp_assert(wl->head != NULL);
00452
00453 last = NULL;
00454 current = wl->head;
00455 while (current) {
00456 if (mi->priority == current->priority) {
00457
00458
00459
00460 if (mi->watcher_data == current->watcher_data)
00461 return SNMPERR_VALUE;
00462 } else if (mi->priority > current->priority) {
00463 break;
00464 }
00465 last = current;
00466 current = current->next;
00467 }
00468 if (NULL == last) {
00469 mi->next = wl->head;
00470 wl->head = mi;
00471 } else {
00472 mi->next = last->next;
00473 last->next = mi;
00474 }
00475 } else {
00476
00477
00478
00479
00480 wl = SNMP_MALLOC_TYPEDEF(watcher_list);
00481 if (NULL == wl)
00482 return SNMPERR_MALLOC;
00483
00484
00485
00486
00487 wl->monitored_object.len = oid_len;
00488 wl->monitored_object.oids = malloc(sizeof(oid) * oid_len);
00489 if (NULL == wl->monitored_object.oids) {
00490 free(wl);
00491 return SNMPERR_MALLOC;
00492 }
00493 memcpy(wl->monitored_object.oids, object, sizeof(oid) * oid_len);
00494
00495
00496
00497
00498 wl->head = mi;
00499 mi->next = NULL;
00500 rc = CONTAINER_INSERT(monitored_objects, wl);
00501 if (rc) {
00502 free(wl->monitored_object.oids);
00503 free(wl);
00504 return rc;
00505 }
00506 }
00507 return rc;
00508 }
00509
00528 static int
00529 check_registered(unsigned int event, oid * o, int o_l,
00530 watcher_list ** pWl, monitor_info ** pMi)
00531 {
00532 watcher_list *wl;
00533 monitor_info *mi;
00534
00535 netsnmp_assert(need_init == 0);
00536
00537
00538
00539
00540
00541 wl = find_watchers(o, o_l);
00542 if (pWl)
00543 *pWl = wl;
00544 if (NULL == wl)
00545 return 0;
00546
00547
00548
00549
00550 for (mi = wl->head; mi; mi = mi->next) {
00551
00552 if (mi->events & event) {
00553 if (pMi)
00554 *pMi = mi;
00555 return TRUE;
00556 }
00557 }
00558
00559 return 0;
00560 }
00561
00565 inline void
00566 insert_ready(callback_placeholder * new_cbr)
00567 {
00568 callback_placeholder *current_cbr, *last_cbr;
00569
00570
00571
00572
00573 last_cbr = NULL;
00574 current_cbr = callback_ready_list;
00575 while (current_cbr) {
00576
00577 if (new_cbr->mi->priority > current_cbr->mi->priority)
00578 break;
00579
00580 last_cbr = current_cbr;
00581 current_cbr = current_cbr->next;
00582 }
00583 if (NULL == last_cbr) {
00584 new_cbr->next = callback_ready_list;
00585 callback_ready_list = new_cbr;
00586 } else {
00587 new_cbr->next = last_cbr->next;
00588 last_cbr->next = new_cbr;
00589 }
00590 }
00591
00598 static void
00599 move_pending_to_ready(void)
00600 {
00601
00602
00603
00604
00605 while (callback_pending_list) {
00606
00607 watcher_list *wl;
00608 monitor_info *mi;
00609 netsnmp_monitor_callback_header *cbp;
00610
00611
00612
00613
00614 cbp = callback_pending_list;
00615 callback_pending_list = cbp->private;
00617 if (0 == check_registered(cbp->event, cbp->monitored_object.oids,
00618 cbp->monitored_object.len, &wl,
00619 &mi)) {
00620
00621
00622
00623
00624 free(cbp);
00625 continue;
00626 }
00627
00628
00629
00630
00631
00632 for (; mi; mi = mi->next) {
00633
00634 callback_placeholder *new_cbr;
00635
00636 if (0 == (mi->events & cbp->event))
00637 continue;
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 new_cbr = SNMP_MALLOC_TYPEDEF(callback_placeholder);
00651 if (NULL == new_cbr) {
00652 snmp_log(LOG_ERR, "malloc failed, callback dropped.");
00653 continue;
00654 }
00655 new_cbr->cbh = cbp;
00656 new_cbr->mi = mi;
00657 ++cbp->refs;
00658
00659
00660
00661
00662 insert_ready(new_cbr);
00663
00664 }
00665 }
00667 netsnmp_assert(callback_pending_list == NULL);
00668 }
00669
00670
00671 #if defined TESTING_OBJECT_MONITOR
00672
00673
00674
00675
00676
00677 void
00678 dummy_callback(netsnmp_monitor_callback_header * cbh)
00679 {
00680 printf("Callback received.\n");
00681 }
00682
00683 void
00684 dump_watchers(netsnmp_index *oah, void *)
00685 {
00686 watcher_list *wl = (watcher_list *) oah;
00687 netsnmp_monitor_callback_header *cbh = wl->head;
00688
00689 printf("Watcher List for OID ");
00690 print_objid(wl->hdr->oids, wl->hdr->len);
00691 printf("\n");
00692
00693 while (cbh) {
00694
00695 printf("Priority = %d;, Events = %d; Watcher Data = 0x%x\n",
00696 cbh->priority, cbh->events, cbh->watcher_data);
00697
00698 cbh = cbh->private;
00699 }
00700 }
00701
00702 void
00703 main(int argc, char **argv)
00704 {
00705
00706 oid object[3] = { 1, 3, 6 };
00707 int object_len = 3;
00708 int rc;
00709
00710
00711
00712
00713 netsnmp_monitor_init();
00714
00715
00716
00717
00718 rc = netsnmp_monitor_register(object, object_len, 0,
00719 EVENT_ROW_ADD, (void *) 0xdeadbeef,
00720 dummy_callback);
00721 printf("insert an object: %d\n", rc);
00722
00723
00724
00725
00726 netsnmp_monitor_register(object, object_len, 10,
00727 EVENT_ROW_ADD, (void *) 0xdeadbeef,
00728 dummy_callback);
00729 printf("insert same object, new priority: %d\n", rc);
00730
00731
00732
00733
00734 netsnmp_monitor_register(object, object_len, 10,
00735 EVENT_ROW_ADD, (void *) 0xbeefdead,
00736 dummy_callback);
00737 printf("insert same object, same priority, new data: %d\n", rc);
00738
00739
00740
00741
00742 netsnmp_monitor_register(object, object_len, 10,
00743 EVENT_ROW_ADD, (void *) 0xbeefdead,
00744 dummy_callback);
00745 printf("insert same object, same priority, new data: %d\n", rc);
00746
00747
00748
00749
00750
00751 CONTAINER_FOR_EACH(monitored_objects, dump_watchers, NULL);
00752 }
00753 #endif