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 struct timeval t_now; 00201 00202 gettimeofday(&t_now, NULL); 00203 00204 for (a = thealarms; a != NULL; a = a->next) { 00205 /* check for time delta skew */ 00206 if ((a->t_next.tv_sec - t_now.tv_sec) > a->t.tv_sec) 00207 { 00208 DEBUGMSGTL(("time_skew", "Time delta too big (%ld seconds), should be %ld seconds - fixing\n", 00209 (long)(a->t_next.tv_sec - t_now.tv_sec), (long)a->t.tv_sec)); 00210 a->t_next.tv_sec = t_now.tv_sec + a->t.tv_sec; 00211 a->t_next.tv_usec = t_now.tv_usec + a->t.tv_usec; 00212 } 00213 if (lowest == NULL) { 00214 lowest = a; 00215 } else if (a->t_next.tv_sec == lowest->t_next.tv_sec) { 00216 if (a->t_next.tv_usec < lowest->t_next.tv_usec) { 00217 lowest = a; 00218 } 00219 } else if (a->t_next.tv_sec < lowest->t_next.tv_sec) { 00220 lowest = a; 00221 } 00222 } 00223 return lowest; 00224 } 00225 00226 struct snmp_alarm * 00227 sa_find_specific(unsigned int clientreg) 00228 { 00229 struct snmp_alarm *sa_ptr; 00230 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_ptr->next) { 00231 if (sa_ptr->clientreg == clientreg) { 00232 return sa_ptr; 00233 } 00234 } 00235 return NULL; 00236 } 00237 00238 void 00239 run_alarms(void) 00240 { 00241 int done = 0; 00242 struct snmp_alarm *a = NULL; 00243 unsigned int clientreg; 00244 struct timeval t_now; 00245 00246 /* 00247 * Loop through everything we have repeatedly looking for the next thing to 00248 * call until all events are finally in the future again. 00249 */ 00250 00251 while (!done) { 00252 if ((a = sa_find_next()) == NULL) { 00253 return; 00254 } 00255 00256 gettimeofday(&t_now, NULL); 00257 00258 if ((a->t_next.tv_sec < t_now.tv_sec) || 00259 ((a->t_next.tv_sec == t_now.tv_sec) && 00260 (a->t_next.tv_usec < t_now.tv_usec))) { 00261 clientreg = a->clientreg; 00262 DEBUGMSGTL(("snmp_alarm", "run alarm %d\n", clientreg)); 00263 (*(a->thecallback)) (clientreg, a->clientarg); 00264 DEBUGMSGTL(("snmp_alarm", "alarm %d completed\n", clientreg)); 00265 00266 if ((a = sa_find_specific(clientreg)) != NULL) { 00267 a->t_last.tv_sec = t_now.tv_sec; 00268 a->t_last.tv_usec = t_now.tv_usec; 00269 a->t_next.tv_sec = 0; 00270 a->t_next.tv_usec = 0; 00271 sa_update_entry(a); 00272 } else { 00273 DEBUGMSGTL(("snmp_alarm", "alarm %d deleted itself\n", 00274 clientreg)); 00275 } 00276 } else { 00277 done = 1; 00278 } 00279 } 00280 } 00281 00282 00283 00284 RETSIGTYPE 00285 alarm_handler(int a) 00286 { 00287 run_alarms(); 00288 set_an_alarm(); 00289 } 00290 00291 00292 00293 int 00294 get_next_alarm_delay_time(struct timeval *delta) 00295 { 00296 struct snmp_alarm *sa_ptr; 00297 struct timeval t_diff, t_now; 00298 00299 sa_ptr = sa_find_next(); 00300 00301 if (sa_ptr) { 00302 gettimeofday(&t_now, NULL); 00303 00304 if ((t_now.tv_sec > sa_ptr->t_next.tv_sec) || 00305 ((t_now.tv_sec == sa_ptr->t_next.tv_sec) && 00306 (t_now.tv_usec > sa_ptr->t_next.tv_usec))) { 00307 /* 00308 * Time has already passed. Return the smallest possible amount of 00309 * time. 00310 */ 00311 delta->tv_sec = 0; 00312 delta->tv_usec = 1; 00313 return sa_ptr->clientreg; 00314 } else { 00315 /* 00316 * Time is still in the future. 00317 */ 00318 t_diff.tv_sec = sa_ptr->t_next.tv_sec - t_now.tv_sec; 00319 t_diff.tv_usec = sa_ptr->t_next.tv_usec - t_now.tv_usec; 00320 00321 while (t_diff.tv_usec < 0) { 00322 t_diff.tv_sec -= 1; 00323 t_diff.tv_usec += 1000000; 00324 } 00325 00326 delta->tv_sec = t_diff.tv_sec; 00327 delta->tv_usec = t_diff.tv_usec; 00328 return sa_ptr->clientreg; 00329 } 00330 } 00331 00332 /* 00333 * Nothing Left. 00334 */ 00335 return 0; 00336 } 00337 00338 00339 void 00340 set_an_alarm(void) 00341 { 00342 struct timeval delta; 00343 int nextalarm = get_next_alarm_delay_time(&delta); 00344 00345 /* 00346 * We don't use signals if they asked us nicely not to. It's expected 00347 * they'll check the next alarm time and do their own calling of 00348 * run_alarms(). 00349 */ 00350 00351 if (nextalarm && !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00352 NETSNMP_DS_LIB_ALARM_DONT_USE_SIG)) { 00353 #ifndef WIN32 00354 # ifdef HAVE_SETITIMER 00355 struct itimerval it; 00356 00357 it.it_value.tv_sec = delta.tv_sec; 00358 it.it_value.tv_usec = delta.tv_usec; 00359 it.it_interval.tv_sec = 0; 00360 it.it_interval.tv_usec = 0; 00361 00362 signal(SIGALRM, alarm_handler); 00363 setitimer(ITIMER_REAL, &it, NULL); 00364 DEBUGMSGTL(("snmp_alarm", "schedule alarm %d in %ld.%03ld seconds\n", 00365 nextalarm, delta.tv_sec, (delta.tv_usec / 1000))); 00366 # else /* HAVE_SETITIMER */ 00367 # ifdef SIGALRM 00368 signal(SIGALRM, alarm_handler); 00369 alarm(delta.tv_sec); 00370 DEBUGMSGTL(("snmp_alarm", 00371 "schedule alarm %d in roughly %ld seconds\n", nextalarm, 00372 delta.tv_sec)); 00373 # endif /* SIGALRM */ 00374 # endif /* HAVE_SETITIMER */ 00375 #endif /* WIN32 */ 00376 00377 } else { 00378 DEBUGMSGTL(("snmp_alarm", "no alarms found to schedule\n")); 00379 } 00380 } 00381 00382 00414 unsigned int 00415 snmp_alarm_register(unsigned int when, unsigned int flags, 00416 SNMPAlarmCallback * thecallback, void *clientarg) 00417 { 00418 struct snmp_alarm **sa_pptr; 00419 if (thealarms != NULL) { 00420 for (sa_pptr = &thealarms; (*sa_pptr) != NULL; 00421 sa_pptr = &((*sa_pptr)->next)); 00422 } else { 00423 sa_pptr = &thealarms; 00424 } 00425 00426 *sa_pptr = SNMP_MALLOC_STRUCT(snmp_alarm); 00427 if (*sa_pptr == NULL) 00428 return 0; 00429 00430 if (0 == when) { 00431 (*sa_pptr)->t.tv_sec = 0; 00432 (*sa_pptr)->t.tv_usec = 1; 00433 } else { 00434 (*sa_pptr)->t.tv_sec = when; 00435 (*sa_pptr)->t.tv_usec = 0; 00436 } 00437 (*sa_pptr)->flags = flags; 00438 (*sa_pptr)->clientarg = clientarg; 00439 (*sa_pptr)->thecallback = thecallback; 00440 (*sa_pptr)->clientreg = regnum++; 00441 (*sa_pptr)->next = NULL; 00442 sa_update_entry(*sa_pptr); 00443 00444 DEBUGMSGTL(("snmp_alarm", 00445 "registered alarm %d, t = %ld.%03ld, flags=0x%02x\n", 00446 (*sa_pptr)->clientreg, (*sa_pptr)->t.tv_sec, 00447 ((*sa_pptr)->t.tv_usec / 1000), (*sa_pptr)->flags)); 00448 00449 if (start_alarms) 00450 set_an_alarm(); 00451 return (*sa_pptr)->clientreg; 00452 } 00453 00454 00491 unsigned int 00492 snmp_alarm_register_hr(struct timeval t, unsigned int flags, 00493 SNMPAlarmCallback * cb, void *cd) 00494 { 00495 struct snmp_alarm **s = NULL; 00496 00497 for (s = &(thealarms); *s != NULL; s = &((*s)->next)); 00498 00499 *s = SNMP_MALLOC_STRUCT(snmp_alarm); 00500 if (*s == NULL) { 00501 return 0; 00502 } 00503 00504 (*s)->t.tv_sec = t.tv_sec; 00505 (*s)->t.tv_usec = t.tv_usec; 00506 (*s)->flags = flags; 00507 (*s)->clientarg = cd; 00508 (*s)->thecallback = cb; 00509 (*s)->clientreg = regnum++; 00510 (*s)->next = NULL; 00511 00512 sa_update_entry(*s); 00513 00514 DEBUGMSGTL(("snmp_alarm", 00515 "registered alarm %d, t = %ld.%03ld, flags=0x%02x\n", 00516 (*s)->clientreg, (*s)->t.tv_sec, ((*s)->t.tv_usec / 1000), 00517 (*s)->flags)); 00518 00519 if (start_alarms) { 00520 set_an_alarm(); 00521 } 00522 00523 return (*s)->clientreg; 00524 }
1.5.7.1
Last modified: Tuesday, 23-Dec-2025 17:22:04 UTC
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.