00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00019 #include <net-snmp/net-snmp-config.h>
00020
00021 #if HAVE_UNISTD_H
00022 #include <unistd.h>
00023 #endif
00024 #include <signal.h>
00025 #if HAVE_STDLIB_H
00026 #include <stdlib.h>
00027 #endif
00028 #include <sys/types.h>
00029 #if HAVE_NETINET_IN_H
00030 #include <netinet/in.h>
00031 #endif
00032 #if HAVE_STRING_H
00033 #include <string.h>
00034 #endif
00035
00036 #if TIME_WITH_SYS_TIME
00037 # ifdef WIN32
00038 # include <sys/timeb.h>
00039 # else
00040 # include <sys/time.h>
00041 # endif
00042 # include <time.h>
00043 #else
00044 # if HAVE_SYS_TIME_H
00045 # include <sys/time.h>
00046 # else
00047 # include <time.h>
00048 # endif
00049 #endif
00050 #if HAVE_WINSOCK_H
00051 #include <winsock.h>
00052 #endif
00053
00054 #if HAVE_DMALLOC_H
00055 #include <dmalloc.h>
00056 #endif
00057
00058 #include <net-snmp/types.h>
00059 #include <net-snmp/output_api.h>
00060 #include <net-snmp/config_api.h>
00061 #include <net-snmp/utilities.h>
00062
00063 #include <net-snmp/library/snmp_api.h>
00064 #include <net-snmp/library/callback.h>
00065 #include <net-snmp/library/snmp_alarm.h>
00066
00067 static struct snmp_alarm *thealarms = NULL;
00068 static int start_alarms = 0;
00069 static unsigned int regnum = 1;
00070
00071 int
00072 init_alarm_post_config(int majorid, int minorid, void *serverarg,
00073 void *clientarg)
00074 {
00075 start_alarms = 1;
00076 set_an_alarm();
00077 return SNMPERR_SUCCESS;
00078 }
00079
00080 void
00081 init_snmp_alarm(void)
00082 {
00083 start_alarms = 0;
00084 snmp_register_callback(SNMP_CALLBACK_LIBRARY,
00085 SNMP_CALLBACK_POST_READ_CONFIG,
00086 init_alarm_post_config, NULL);
00087 }
00088
00089 void
00090 sa_update_entry(struct snmp_alarm *a)
00091 {
00092 if (a->t_last.tv_sec == 0 && a->t_last.tv_usec == 0) {
00093 struct timeval t_now;
00094
00095
00096
00097 gettimeofday(&t_now, NULL);
00098
00099 a->t_last.tv_sec = t_now.tv_sec;
00100 a->t_last.tv_usec = t_now.tv_usec;
00101
00102 a->t_next.tv_sec = t_now.tv_sec + a->t.tv_sec;
00103 a->t_next.tv_usec = t_now.tv_usec + a->t.tv_usec;
00104
00105 while (a->t_next.tv_usec >= 1000000) {
00106 a->t_next.tv_usec -= 1000000;
00107 a->t_next.tv_sec += 1;
00108 }
00109 } else if (a->t_next.tv_sec == 0 && a->t_next.tv_usec == 0) {
00110
00111
00112
00113 if (a->flags & SA_REPEAT) {
00114 if (a->t.tv_sec == 0 && a->t.tv_usec == 0) {
00115 DEBUGMSGTL(("snmp_alarm",
00116 "update_entry: illegal interval specified\n"));
00117 snmp_alarm_unregister(a->clientreg);
00118 return;
00119 }
00120
00121 a->t_next.tv_sec = a->t_last.tv_sec + a->t.tv_sec;
00122 a->t_next.tv_usec = a->t_last.tv_usec + a->t.tv_usec;
00123
00124 while (a->t_next.tv_usec >= 1000000) {
00125 a->t_next.tv_usec -= 1000000;
00126 a->t_next.tv_sec += 1;
00127 }
00128 } else {
00129
00130
00131
00132 snmp_alarm_unregister(a->clientreg);
00133 }
00134 }
00135 }
00136
00150 void
00151 snmp_alarm_unregister(unsigned int clientreg)
00152 {
00153 struct snmp_alarm *sa_ptr, **prevNext = &thealarms;
00154
00155 for (sa_ptr = thealarms;
00156 sa_ptr != NULL && sa_ptr->clientreg != clientreg;
00157 sa_ptr = sa_ptr->next) {
00158 prevNext = &(sa_ptr->next);
00159 }
00160
00161 if (sa_ptr != NULL) {
00162 *prevNext = sa_ptr->next;
00163 DEBUGMSGTL(("snmp_alarm", "unregistered alarm %d\n",
00164 sa_ptr->clientreg));
00165
00166
00167
00168 free(sa_ptr);
00169 } else {
00170 DEBUGMSGTL(("snmp_alarm", "no alarm %d to unregister\n", clientreg));
00171 }
00172 }
00173
00183 void
00184 snmp_alarm_unregister_all(void)
00185 {
00186 struct snmp_alarm *sa_ptr, *sa_tmp;
00187
00188 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_tmp) {
00189 sa_tmp = sa_ptr->next;
00190 free(sa_ptr);
00191 }
00192 DEBUGMSGTL(("snmp_alarm", "ALL alarms unregistered\n"));
00193 thealarms = NULL;
00194 }
00195
00196 struct snmp_alarm *
00197 sa_find_next(void)
00198 {
00199 struct snmp_alarm *a, *lowest = NULL;
00200
00201 for (a = thealarms; a != NULL; a = a->next) {
00202 if (lowest == NULL) {
00203 lowest = a;
00204 } else if (a->t_next.tv_sec == lowest->t_next.tv_sec) {
00205 if (a->t_next.tv_usec < lowest->t_next.tv_usec) {
00206 lowest = a;
00207 }
00208 } else if (a->t_next.tv_sec < lowest->t_next.tv_sec) {
00209 lowest = a;
00210 }
00211 }
00212 return lowest;
00213 }
00214
00215 struct snmp_alarm *
00216 sa_find_specific(unsigned int clientreg)
00217 {
00218 struct snmp_alarm *sa_ptr;
00219 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_ptr->next) {
00220 if (sa_ptr->clientreg == clientreg) {
00221 return sa_ptr;
00222 }
00223 }
00224 return NULL;
00225 }
00226
00227 void
00228 run_alarms(void)
00229 {
00230 int done = 0;
00231 struct snmp_alarm *a = NULL;
00232 unsigned int clientreg;
00233 struct timeval t_now;
00234
00235
00236
00237
00238
00239
00240 while (!done) {
00241 if ((a = sa_find_next()) == NULL) {
00242 return;
00243 }
00244
00245 gettimeofday(&t_now, NULL);
00246
00247 if ((a->t_next.tv_sec < t_now.tv_sec) ||
00248 ((a->t_next.tv_sec == t_now.tv_sec) &&
00249 (a->t_next.tv_usec < t_now.tv_usec))) {
00250 clientreg = a->clientreg;
00251 DEBUGMSGTL(("snmp_alarm", "run alarm %d\n", clientreg));
00252 (*(a->thecallback)) (clientreg, a->clientarg);
00253 DEBUGMSGTL(("snmp_alarm", "alarm %d completed\n", clientreg));
00254
00255 if ((a = sa_find_specific(clientreg)) != NULL) {
00256 a->t_last.tv_sec = t_now.tv_sec;
00257 a->t_last.tv_usec = t_now.tv_usec;
00258 a->t_next.tv_sec = 0;
00259 a->t_next.tv_usec = 0;
00260 sa_update_entry(a);
00261 } else {
00262 DEBUGMSGTL(("snmp_alarm", "alarm %d deleted itself\n",
00263 clientreg));
00264 }
00265 } else {
00266 done = 1;
00267 }
00268 }
00269 }
00270
00271
00272
00273 RETSIGTYPE
00274 alarm_handler(int a)
00275 {
00276 run_alarms();
00277 set_an_alarm();
00278 }
00279
00280
00281
00282 int
00283 get_next_alarm_delay_time(struct timeval *delta)
00284 {
00285 struct snmp_alarm *sa_ptr;
00286 struct timeval t_diff, t_now;
00287
00288 sa_ptr = sa_find_next();
00289
00290 if (sa_ptr) {
00291 gettimeofday(&t_now, 0);
00292
00293 if ((t_now.tv_sec > sa_ptr->t_next.tv_sec) ||
00294 ((t_now.tv_sec == sa_ptr->t_next.tv_sec) &&
00295 (t_now.tv_usec > sa_ptr->t_next.tv_usec))) {
00296
00297
00298
00299
00300 delta->tv_sec = 0;
00301 delta->tv_usec = 1;
00302 return sa_ptr->clientreg;
00303 } else {
00304
00305
00306
00307 t_diff.tv_sec = sa_ptr->t_next.tv_sec - t_now.tv_sec;
00308 t_diff.tv_usec = sa_ptr->t_next.tv_usec - t_now.tv_usec;
00309
00310 while (t_diff.tv_usec < 0) {
00311 t_diff.tv_sec -= 1;
00312 t_diff.tv_usec += 1000000;
00313 }
00314
00315 delta->tv_sec = t_diff.tv_sec;
00316 delta->tv_usec = t_diff.tv_usec;
00317 return sa_ptr->clientreg;
00318 }
00319 }
00320
00321
00322
00323
00324 return 0;
00325 }
00326
00327
00328 void
00329 set_an_alarm(void)
00330 {
00331 struct timeval delta;
00332 int nextalarm = get_next_alarm_delay_time(&delta);
00333
00334
00335
00336
00337
00338
00339
00340 if (nextalarm && !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID,
00341 NETSNMP_DS_LIB_ALARM_DONT_USE_SIG)) {
00342 #ifndef WIN32
00343 # ifdef HAVE_SETITIMER
00344 struct itimerval it;
00345
00346 it.it_value.tv_sec = delta.tv_sec;
00347 it.it_value.tv_usec = delta.tv_usec;
00348 it.it_interval.tv_sec = 0;
00349 it.it_interval.tv_usec = 0;
00350
00351 signal(SIGALRM, alarm_handler);
00352 setitimer(ITIMER_REAL, &it, NULL);
00353 DEBUGMSGTL(("snmp_alarm", "schedule alarm %d in %d.%03d seconds\n",
00354 nextalarm, delta.tv_sec, (delta.tv_usec / 1000)));
00355 # else
00356 # ifdef SIGALRM
00357 signal(SIGALRM, alarm_handler);
00358 alarm(delta.tv_sec);
00359 DEBUGMSGTL(("snmp_alarm",
00360 "schedule alarm %d in roughly %d seconds\n", nextalarm,
00361 delta.tv_sec));
00362 # endif
00363 # endif
00364 #endif
00365
00366 } else {
00367 DEBUGMSGTL(("snmp_alarm", "no alarms found to schedule\n"));
00368 }
00369 }
00370
00371
00403 unsigned int
00404 snmp_alarm_register(unsigned int when, unsigned int flags,
00405 SNMPAlarmCallback * thecallback, void *clientarg)
00406 {
00407 struct snmp_alarm **sa_pptr;
00408 if (thealarms != NULL) {
00409 for (sa_pptr = &thealarms; (*sa_pptr) != NULL;
00410 sa_pptr = &((*sa_pptr)->next));
00411 } else {
00412 sa_pptr = &thealarms;
00413 }
00414
00415 *sa_pptr = SNMP_MALLOC_STRUCT(snmp_alarm);
00416 if (*sa_pptr == NULL)
00417 return 0;
00418
00419 if (0 == when) {
00420 (*sa_pptr)->t.tv_sec = 0;
00421 (*sa_pptr)->t.tv_usec = 1;
00422 } else {
00423 (*sa_pptr)->t.tv_sec = when;
00424 (*sa_pptr)->t.tv_usec = 0;
00425 }
00426 (*sa_pptr)->flags = flags;
00427 (*sa_pptr)->clientarg = clientarg;
00428 (*sa_pptr)->thecallback = thecallback;
00429 (*sa_pptr)->clientreg = regnum++;
00430 (*sa_pptr)->next = NULL;
00431 sa_update_entry(*sa_pptr);
00432
00433 DEBUGMSGTL(("snmp_alarm",
00434 "registered alarm %d, t = %d.%03d, flags=0x%02x\n",
00435 (*sa_pptr)->clientreg, (*sa_pptr)->t.tv_sec,
00436 ((*sa_pptr)->t.tv_usec / 1000), (*sa_pptr)->flags));
00437
00438 if (start_alarms)
00439 set_an_alarm();
00440 return (*sa_pptr)->clientreg;
00441 }
00442
00443
00480 unsigned int
00481 snmp_alarm_register_hr(struct timeval t, unsigned int flags,
00482 SNMPAlarmCallback * cb, void *cd)
00483 {
00484 struct snmp_alarm **s = NULL;
00485
00486 for (s = &(thealarms); *s != NULL; s = &((*s)->next));
00487
00488 *s = SNMP_MALLOC_STRUCT(snmp_alarm);
00489 if (*s == NULL) {
00490 return 0;
00491 }
00492
00493 (*s)->t.tv_sec = t.tv_sec;
00494 (*s)->t.tv_usec = t.tv_usec;
00495 (*s)->flags = flags;
00496 (*s)->clientarg = cd;
00497 (*s)->thecallback = cb;
00498 (*s)->clientreg = regnum++;
00499 (*s)->next = NULL;
00500
00501 sa_update_entry(*s);
00502
00503 DEBUGMSGTL(("snmp_alarm",
00504 "registered alarm %d, t = %d.%03d, flags=0x%02x\n",
00505 (*s)->clientreg, (*s)->t.tv_sec, ((*s)->t.tv_usec / 1000),
00506 (*s)->flags));
00507
00508 if (start_alarms) {
00509 set_an_alarm();
00510 }
00511
00512 return (*s)->clientreg;
00513 }