net-snmp
5.4.1
|
00001 /* 00002 * snmp_alarm.c: 00003 */ 00004 /* Portions of this file are subject to the following copyright(s). See 00005 * the Net-SNMP's COPYING file for more details and other copyrights 00006 * that may apply: 00007 */ 00008 /* 00009 * Portions of this file are copyrighted by: 00010 * Copyright © 2003 Sun Microsystems, Inc. All rights reserved. 00011 * Use is subject to license terms specified in the COPYING file 00012 * distributed with the Net-SNMP package. 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 * Never been called yet, call time `t' from now. 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 * We've been called but not reset for the next call. 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 * Single time call, remove it. 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 * Note: do not free the clientarg, its the clients responsibility 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 * Loop through everything we have repeatedly looking for the next thing to 00237 * call until all events are finally in the future again. 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 * Time has already passed. Return the smallest possible amount of 00298 * time. 00299 */ 00300 delta->tv_sec = 0; 00301 delta->tv_usec = 1; 00302 return sa_ptr->clientreg; 00303 } else { 00304 /* 00305 * Time is still in the future. 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 * Nothing Left. 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 * We don't use signals if they asked us nicely not to. It's expected 00336 * they'll check the next alarm time and do their own calling of 00337 * run_alarms(). 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 /* HAVE_SETITIMER */ 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 /* SIGALRM */ 00363 # endif /* HAVE_SETITIMER */ 00364 #endif /* WIN32 */ 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 }