00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00019 #include <net-snmp/net-snmp-config.h>
00020 #include <sys/types.h>
00021 #include <stdio.h>
00022 #if HAVE_STDLIB_H
00023 #include <stdlib.h>
00024 #endif
00025 #if HAVE_WINSOCK_H
00026 #include <winsock.h>
00027 #endif
00028 #if HAVE_NETINET_IN_H
00029 #include <netinet/in.h>
00030 #endif
00031 #if HAVE_STRING_H
00032 #include <string.h>
00033 #else
00034 #include <strings.h>
00035 #endif
00036
00037 #if HAVE_DMALLOC_H
00038 #include <dmalloc.h>
00039 #endif
00040
00041 #if HAVE_SYS_SOCKET_H
00042 #include <sys/socket.h>
00043 #endif
00044 #if HAVE_SYS_TIME_H
00045 #include <sys/time.h>
00046 #endif
00047
00048 #include <net-snmp/types.h>
00049 #include <net-snmp/output_api.h>
00050 #include <net-snmp/utilities.h>
00051
00052 #include <net-snmp/library/callback.h>
00053 #include <net-snmp/library/snmp_api.h>
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064 static int _callback_need_init = 1;
00065 static struct snmp_gen_callback
00066 *thecallbacks[MAX_CALLBACK_IDS][MAX_CALLBACK_SUBIDS];
00067
00068 #define CALLBACK_NAME_LOGGING 1
00069 #ifdef CALLBACK_NAME_LOGGING
00070 static const char *types[MAX_CALLBACK_IDS] = { "LIB", "APP" };
00071 static const char *lib[MAX_CALLBACK_SUBIDS] = {
00072 "POST_READ_CONFIG",
00073 "STORE_DATA",
00074 "SHUTDOWN",
00075 "POST_PREMIB_READ_CONFIG",
00076 "LOGGING",
00077 "SESSION_INIT",
00078 NULL,
00079 NULL,
00080 NULL,
00081 NULL,
00082 NULL,
00083 NULL,
00084 NULL,
00085 NULL,
00086 NULL,
00087 NULL
00088 };
00089 #endif
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101 #define LOCK_PER_CALLBACK_SUBID 1
00102 #ifdef LOCK_PER_CALLBACK_SUBID
00103 static int _locks[MAX_CALLBACK_IDS][MAX_CALLBACK_SUBIDS];
00104 #define CALLBACK_LOCK(maj,min) ++_locks[maj][min]
00105 #define CALLBACK_UNLOCK(maj,min) --_locks[maj][min]
00106 #define CALLBACK_LOCK_COUNT(maj,min) _locks[maj][min]
00107 #else
00108 static int _lock;
00109 #define CALLBACK_LOCK(maj,min) ++_lock
00110 #define CALLBACK_UNLOCK(maj,min) --_lock
00111 #define CALLBACK_LOCK_COUNT(maj,min) _lock
00112 #endif
00113
00114 NETSNMP_STATIC_INLINE int
00115 _callback_lock(int major, int minor, const char* warn, int assert)
00116 {
00117 int lock_holded=0;
00118 struct timeval lock_time = { 0, 1000 };
00119
00120 #ifdef NETSNMP_PARANOID_LEVEL_HIGH
00121 if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
00122 netsnmp_assert("bad callback id");
00123 return 1;
00124 }
00125 #endif
00126
00127 #ifdef CALLBACK_NAME_LOGGING
00128 DEBUGMSGTL(("9:callback:lock", "locked (%s,%s)\n",
00129 types[major], (SNMP_CALLBACK_LIBRARY == major) ?
00130 SNMP_STRORNULL(lib[minor]) : "null"));
00131 #endif
00132 while (CALLBACK_LOCK_COUNT(major,minor) >= 1 && ++lock_holded < 100)
00133 select(0, NULL, NULL, NULL, &lock_time);
00134
00135 if(lock_holded >= 100) {
00136 if (NULL != warn)
00137 snmp_log(LOG_WARNING,
00138 "lock in _callback_lock sleeps more than 100 milliseconds in %s\n", warn);
00139 if (assert)
00140 netsnmp_assert(lock_holded < 100);
00141
00142 return 1;
00143 }
00144
00145 CALLBACK_LOCK(major,minor);
00146 return 0;
00147 }
00148
00149 NETSNMP_STATIC_INLINE void
00150 _callback_unlock(int major, int minor)
00151 {
00152 #ifdef NETSNMP_PARANOID_LEVEL_HIGH
00153 if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
00154 netsnmp_assert("bad callback id");
00155 return;
00156 }
00157 #endif
00158
00159 CALLBACK_UNLOCK(major,minor);
00160
00161 #ifdef CALLBACK_NAME_LOGGING
00162 DEBUGMSGTL(("9:callback:lock", "unlocked (%s,%s)\n",
00163 types[major], (SNMP_CALLBACK_LIBRARY == major) ?
00164 SNMP_STRORNULL(lib[minor]) : "null"));
00165 #endif
00166 }
00167
00168
00169
00170
00171
00172 void
00173 init_callbacks(void)
00174 {
00175
00176
00177
00178
00179
00180 if (0 == _callback_need_init)
00181 return;
00182
00183 _callback_need_init = 0;
00184
00185 memset(thecallbacks, 0, sizeof(thecallbacks));
00186 #ifdef LOCK_PER_CALLBACK_SUBID
00187 memset(_locks, 0, sizeof(_locks));
00188 #else
00189 _lock = 0;
00190 #endif
00191
00192 DEBUGMSGTL(("callback", "initialized\n"));
00193 }
00194
00229 int
00230 snmp_register_callback(int major, int minor, SNMPCallback * new_callback,
00231 void *arg)
00232 {
00233 return netsnmp_register_callback( major, minor, new_callback, arg,
00234 NETSNMP_CALLBACK_DEFAULT_PRIORITY);
00235 }
00236
00237 int
00238 netsnmp_register_callback(int major, int minor, SNMPCallback * new_callback,
00239 void *arg, int priority)
00240 {
00241 struct snmp_gen_callback *newscp = NULL, *scp = NULL;
00242 struct snmp_gen_callback **prevNext = &(thecallbacks[major][minor]);
00243
00244 if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
00245 return SNMPERR_GENERR;
00246 }
00247
00248 if (_callback_need_init)
00249 init_callbacks();
00250
00251 _callback_lock(major,minor, "netsnmp_register_callback", 1);
00252
00253 if ((newscp = SNMP_MALLOC_STRUCT(snmp_gen_callback)) == NULL) {
00254 _callback_unlock(major,minor);
00255 return SNMPERR_GENERR;
00256 } else {
00257 newscp->priority = priority;
00258 newscp->sc_client_arg = arg;
00259 newscp->sc_callback = new_callback;
00260 newscp->next = NULL;
00261
00262 for (scp = thecallbacks[major][minor]; scp != NULL;
00263 scp = scp->next) {
00264 if (newscp->priority < scp->priority) {
00265 newscp->next = scp;
00266 break;
00267 }
00268 prevNext = &(scp->next);
00269 }
00270
00271 *prevNext = newscp;
00272
00273 DEBUGMSGTL(("callback", "registered (%d,%d) at %p with priority %d\n",
00274 major, minor, newscp, priority));
00275 _callback_unlock(major,minor);
00276 return SNMPERR_SUCCESS;
00277 }
00278 }
00279
00297 int
00298 snmp_call_callbacks(int major, int minor, void *caller_arg)
00299 {
00300 struct snmp_gen_callback *scp;
00301 unsigned int count = 0;
00302
00303 if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
00304 return SNMPERR_GENERR;
00305 }
00306
00307 if (_callback_need_init)
00308 init_callbacks();
00309
00310 #ifdef LOCK_PER_CALLBACK_SUBID
00311 _callback_lock(major,minor,"snmp_call_callbacks", 1);
00312 #else
00313
00314
00315
00316
00317
00318 _callback_lock(major,minor, NULL, 0);
00319 #endif
00320
00321 DEBUGMSGTL(("callback", "START calling callbacks for maj=%d min=%d\n",
00322 major, minor));
00323
00324
00325
00326
00327 for (scp = thecallbacks[major][minor]; scp != NULL; scp = scp->next) {
00328
00329
00330
00331
00332 if(NULL == scp->sc_callback)
00333 continue;
00334
00335 DEBUGMSGTL(("callback", "calling a callback for maj=%d min=%d\n",
00336 major, minor));
00337
00338
00339
00340
00341 (*(scp->sc_callback)) (major, minor, caller_arg,
00342 scp->sc_client_arg);
00343 count++;
00344 }
00345
00346 DEBUGMSGTL(("callback",
00347 "END calling callbacks for maj=%d min=%d (%d called)\n",
00348 major, minor, count));
00349
00350 _callback_unlock(major,minor);
00351 return SNMPERR_SUCCESS;
00352 }
00353
00354 int
00355 snmp_count_callbacks(int major, int minor)
00356 {
00357 int count = 0;
00358 struct snmp_gen_callback *scp;
00359
00360 if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
00361 return SNMPERR_GENERR;
00362 }
00363
00364 if (_callback_need_init)
00365 init_callbacks();
00366
00367 for (scp = thecallbacks[major][minor]; scp != NULL; scp = scp->next) {
00368 count++;
00369 }
00370
00371 return count;
00372 }
00373
00374 int
00375 snmp_callback_available(int major, int minor)
00376 {
00377 if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS) {
00378 return SNMPERR_GENERR;
00379 }
00380
00381 if (_callback_need_init)
00382 init_callbacks();
00383
00384 if (thecallbacks[major][minor] != NULL) {
00385 return SNMPERR_SUCCESS;
00386 }
00387
00388 return SNMPERR_GENERR;
00389 }
00390
00417 int
00418 snmp_unregister_callback(int major, int minor, SNMPCallback * target,
00419 void *arg, int matchargs)
00420 {
00421 struct snmp_gen_callback *scp = thecallbacks[major][minor];
00422 struct snmp_gen_callback **prevNext = &(thecallbacks[major][minor]);
00423 int count = 0;
00424
00425 if (major >= MAX_CALLBACK_IDS || minor >= MAX_CALLBACK_SUBIDS)
00426 return SNMPERR_GENERR;
00427
00428 if (_callback_need_init)
00429 init_callbacks();
00430
00431 #ifdef LOCK_PER_CALLBACK_SUBID
00432 _callback_lock(major,minor,"snmp_unregister_callback", 1);
00433 #else
00434
00435
00436
00437
00438 _callback_lock(major,minor,"snmp_unregister_callback", 0);
00439 #endif
00440
00441 while (scp != NULL) {
00442 if ((scp->sc_callback == target) &&
00443 (!matchargs || (scp->sc_client_arg == arg))) {
00444 DEBUGMSGTL(("callback", "unregistering (%d,%d) at %p\n", major,
00445 minor, scp));
00446 if(1 == CALLBACK_LOCK_COUNT(major,minor)) {
00447 *prevNext = scp->next;
00448 SNMP_FREE(scp);
00449 scp = *prevNext;
00450 }
00451 else {
00452 scp->sc_callback = NULL;
00454 }
00455 count++;
00456 } else {
00457 prevNext = &(scp->next);
00458 scp = scp->next;
00459 }
00460 }
00461
00462 _callback_unlock(major,minor);
00463 return count;
00464 }
00465
00473 int
00474 netsnmp_callback_clear_client_arg(void *ptr, int i, int j)
00475 {
00476 struct snmp_gen_callback *scp = NULL;
00477 int rc = 0;
00478
00479
00480
00481
00482
00483
00484
00485 for (; i < MAX_CALLBACK_IDS; i++,j=0) {
00486 for (; j < MAX_CALLBACK_SUBIDS; j++) {
00487 scp = thecallbacks[i][j];
00488 while (scp != NULL) {
00489 if ((NULL != scp->sc_callback) &&
00490 (scp->sc_client_arg != NULL) &&
00491 (scp->sc_client_arg == ptr)) {
00492 DEBUGMSGTL(("9:callback", " clearing %p at [%d,%d]\n", ptr, i, j));
00493 scp->sc_client_arg = NULL;
00494 ++rc;
00495 }
00496 scp = scp->next;
00497 }
00498 }
00499 }
00500
00501 if (0 != rc) {
00502 DEBUGMSGTL(("callback", "removed %d client args\n", rc));
00503 }
00504
00505 return rc;
00506 }
00507
00508 void
00509 clear_callback(void)
00510 {
00511 unsigned int i = 0, j = 0;
00512 struct snmp_gen_callback *scp = NULL;
00513
00514 if (_callback_need_init)
00515 init_callbacks();
00516
00517 DEBUGMSGTL(("callback", "clear callback\n"));
00518 for (i = 0; i < MAX_CALLBACK_IDS; i++) {
00519 for (j = 0; j < MAX_CALLBACK_SUBIDS; j++) {
00520 _callback_lock(i,j, "clear_callback", 1);
00521 scp = thecallbacks[i][j];
00522 while (scp != NULL) {
00523 thecallbacks[i][j] = scp->next;
00524
00525
00526
00527
00528 if ((NULL != scp->sc_callback) &&
00529 (scp->sc_client_arg != NULL)) {
00530 void *tmp_arg;
00531
00532
00533
00534
00535
00536
00537 tmp_arg = scp->sc_client_arg;
00538 scp->sc_client_arg = NULL;
00539 DEBUGMSGTL(("9:callback", " freeing %p at [%d,%d]\n", tmp_arg, i, j));
00540 (void)netsnmp_callback_clear_client_arg(tmp_arg, i, j);
00541 free(tmp_arg);
00542 }
00543 SNMP_FREE(scp);
00544 scp = thecallbacks[i][j];
00545 }
00546 _callback_unlock(i,j);
00547 }
00548 }
00549 }
00550
00551 struct snmp_gen_callback *
00552 snmp_callback_list(int major, int minor)
00553 {
00554 if (_callback_need_init)
00555 init_callbacks();
00556
00557 return (thecallbacks[major][minor]);
00558 }