net-snmp 5.7
|
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 # include <sys/time.h> 00038 # include <time.h> 00039 #else 00040 # if HAVE_SYS_TIME_H 00041 # include <sys/time.h> 00042 # else 00043 # include <time.h> 00044 # endif 00045 #endif 00046 00047 #if HAVE_DMALLOC_H 00048 #include <dmalloc.h> 00049 #endif 00050 00051 #include <net-snmp/types.h> 00052 #include <net-snmp/output_api.h> 00053 #include <net-snmp/config_api.h> 00054 #include <net-snmp/utilities.h> 00055 00056 #include <net-snmp/library/snmp_api.h> 00057 #include <net-snmp/library/callback.h> 00058 #include <net-snmp/library/snmp_alarm.h> 00059 00060 static struct snmp_alarm *thealarms = NULL; 00061 static int start_alarms = 0; 00062 static unsigned int regnum = 1; 00063 00064 int 00065 init_alarm_post_config(int majorid, int minorid, void *serverarg, 00066 void *clientarg) 00067 { 00068 start_alarms = 1; 00069 set_an_alarm(); 00070 return SNMPERR_SUCCESS; 00071 } 00072 00073 void 00074 init_snmp_alarm(void) 00075 { 00076 start_alarms = 0; 00077 snmp_register_callback(SNMP_CALLBACK_LIBRARY, 00078 SNMP_CALLBACK_POST_READ_CONFIG, 00079 init_alarm_post_config, NULL); 00080 } 00081 00082 void 00083 sa_update_entry(struct snmp_alarm *a) 00084 { 00085 if (a->t_last.tv_sec == 0 && a->t_last.tv_usec == 0) { 00086 struct timeval t_now; 00087 /* 00088 * Never been called yet, call time `t' from now. 00089 */ 00090 gettimeofday(&t_now, NULL); 00091 00092 a->t_last.tv_sec = t_now.tv_sec; 00093 a->t_last.tv_usec = t_now.tv_usec; 00094 00095 NETSNMP_TIMERADD(&t_now, &a->t, &a->t_next); 00096 } else if (a->t_next.tv_sec == 0 && a->t_next.tv_usec == 0) { 00097 /* 00098 * We've been called but not reset for the next call. 00099 */ 00100 if (a->flags & SA_REPEAT) { 00101 if (a->t.tv_sec == 0 && a->t.tv_usec == 0) { 00102 DEBUGMSGTL(("snmp_alarm", 00103 "update_entry: illegal interval specified\n")); 00104 snmp_alarm_unregister(a->clientreg); 00105 return; 00106 } 00107 00108 NETSNMP_TIMERADD(&a->t_last, &a->t, &a->t_next); 00109 } else { 00110 /* 00111 * Single time call, remove it. 00112 */ 00113 snmp_alarm_unregister(a->clientreg); 00114 } 00115 } 00116 } 00117 00131 void 00132 snmp_alarm_unregister(unsigned int clientreg) 00133 { 00134 struct snmp_alarm *sa_ptr, **prevNext = &thealarms; 00135 00136 for (sa_ptr = thealarms; 00137 sa_ptr != NULL && sa_ptr->clientreg != clientreg; 00138 sa_ptr = sa_ptr->next) { 00139 prevNext = &(sa_ptr->next); 00140 } 00141 00142 if (sa_ptr != NULL) { 00143 *prevNext = sa_ptr->next; 00144 DEBUGMSGTL(("snmp_alarm", "unregistered alarm %d\n", 00145 sa_ptr->clientreg)); 00146 /* 00147 * Note: do not free the clientarg, its the clients responsibility 00148 */ 00149 free(sa_ptr); 00150 } else { 00151 DEBUGMSGTL(("snmp_alarm", "no alarm %d to unregister\n", clientreg)); 00152 } 00153 } 00154 00164 void 00165 snmp_alarm_unregister_all(void) 00166 { 00167 struct snmp_alarm *sa_ptr, *sa_tmp; 00168 00169 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_tmp) { 00170 sa_tmp = sa_ptr->next; 00171 free(sa_ptr); 00172 } 00173 DEBUGMSGTL(("snmp_alarm", "ALL alarms unregistered\n")); 00174 thealarms = NULL; 00175 } 00176 00177 struct snmp_alarm * 00178 sa_find_next(void) 00179 { 00180 struct snmp_alarm *a, *lowest = NULL; 00181 struct timeval t_now; 00182 00183 gettimeofday(&t_now, NULL); 00184 00185 for (a = thealarms; a != NULL; a = a->next) { 00186 if (!(a->flags & SA_FIRED)) { 00187 /* check for time delta skew */ 00188 if ((a->t_next.tv_sec - t_now.tv_sec) > a->t.tv_sec) 00189 { 00190 DEBUGMSGTL(("time_skew", "Time delta too big (%ld seconds), should be %ld seconds - fixing\n", 00191 (long)(a->t_next.tv_sec - t_now.tv_sec), (long)a->t.tv_sec)); 00192 a->t_next.tv_sec = t_now.tv_sec + a->t.tv_sec; 00193 a->t_next.tv_usec = t_now.tv_usec + a->t.tv_usec; 00194 } 00195 if (lowest == NULL) { 00196 lowest = a; 00197 } else if (a->t_next.tv_sec == lowest->t_next.tv_sec) { 00198 if (a->t_next.tv_usec < lowest->t_next.tv_usec) { 00199 lowest = a; 00200 } 00201 } else if (a->t_next.tv_sec < lowest->t_next.tv_sec) { 00202 lowest = a; 00203 } 00204 } 00205 } 00206 return lowest; 00207 } 00208 00209 NETSNMP_IMPORT struct snmp_alarm *sa_find_specific(unsigned int clientreg); 00210 struct snmp_alarm * 00211 sa_find_specific(unsigned int clientreg) 00212 { 00213 struct snmp_alarm *sa_ptr; 00214 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_ptr->next) { 00215 if (sa_ptr->clientreg == clientreg) { 00216 return sa_ptr; 00217 } 00218 } 00219 return NULL; 00220 } 00221 00222 void 00223 run_alarms(void) 00224 { 00225 int done = 0; 00226 struct snmp_alarm *a = NULL; 00227 unsigned int clientreg; 00228 struct timeval t_now; 00229 00230 /* 00231 * Loop through everything we have repeatedly looking for the next thing to 00232 * call until all events are finally in the future again. 00233 */ 00234 00235 while (!done) { 00236 if ((a = sa_find_next()) == NULL) { 00237 return; 00238 } 00239 00240 gettimeofday(&t_now, NULL); 00241 00242 if (timercmp(&a->t_next, &t_now, <)) { 00243 clientreg = a->clientreg; 00244 a->flags |= SA_FIRED; 00245 DEBUGMSGTL(("snmp_alarm", "run alarm %d\n", clientreg)); 00246 (*(a->thecallback)) (clientreg, a->clientarg); 00247 DEBUGMSGTL(("snmp_alarm", "alarm %d completed\n", clientreg)); 00248 00249 if ((a = sa_find_specific(clientreg)) != NULL) { 00250 a->t_last.tv_sec = t_now.tv_sec; 00251 a->t_last.tv_usec = t_now.tv_usec; 00252 a->t_next.tv_sec = 0; 00253 a->t_next.tv_usec = 0; 00254 a->flags &= ~SA_FIRED; 00255 sa_update_entry(a); 00256 } else { 00257 DEBUGMSGTL(("snmp_alarm", "alarm %d deleted itself\n", 00258 clientreg)); 00259 } 00260 } else { 00261 done = 1; 00262 } 00263 } 00264 } 00265 00266 00267 00268 RETSIGTYPE 00269 alarm_handler(int a) 00270 { 00271 run_alarms(); 00272 set_an_alarm(); 00273 } 00274 00275 00276 00277 int 00278 get_next_alarm_delay_time(struct timeval *delta) 00279 { 00280 struct snmp_alarm *sa_ptr; 00281 struct timeval t_now; 00282 00283 sa_ptr = sa_find_next(); 00284 00285 if (sa_ptr) { 00286 gettimeofday(&t_now, NULL); 00287 00288 if (timercmp(&t_now, &sa_ptr->t_next, >)) { 00289 /* 00290 * Time has already passed. Return the smallest possible amount of 00291 * time. 00292 */ 00293 delta->tv_sec = 0; 00294 delta->tv_usec = 1; 00295 return sa_ptr->clientreg; 00296 } else { 00297 /* 00298 * Time is still in the future. 00299 */ 00300 NETSNMP_TIMERSUB(&sa_ptr->t_next, &t_now, delta); 00301 00302 return sa_ptr->clientreg; 00303 } 00304 } 00305 00306 /* 00307 * Nothing Left. 00308 */ 00309 return 0; 00310 } 00311 00312 00313 void 00314 set_an_alarm(void) 00315 { 00316 struct timeval delta; 00317 int nextalarm = get_next_alarm_delay_time(&delta); 00318 00319 /* 00320 * We don't use signals if they asked us nicely not to. It's expected 00321 * they'll check the next alarm time and do their own calling of 00322 * run_alarms(). 00323 */ 00324 00325 if (nextalarm && !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00326 NETSNMP_DS_LIB_ALARM_DONT_USE_SIG)) { 00327 #ifndef WIN32 00328 # ifdef HAVE_SETITIMER 00329 struct itimerval it; 00330 00331 it.it_value.tv_sec = delta.tv_sec; 00332 it.it_value.tv_usec = delta.tv_usec; 00333 it.it_interval.tv_sec = 0; 00334 it.it_interval.tv_usec = 0; 00335 00336 signal(SIGALRM, alarm_handler); 00337 setitimer(ITIMER_REAL, &it, NULL); 00338 DEBUGMSGTL(("snmp_alarm", "schedule alarm %d in %ld.%03ld seconds\n", 00339 nextalarm, delta.tv_sec, (delta.tv_usec / 1000))); 00340 # else /* HAVE_SETITIMER */ 00341 # ifdef SIGALRM 00342 signal(SIGALRM, alarm_handler); 00343 alarm(delta.tv_sec); 00344 DEBUGMSGTL(("snmp_alarm", 00345 "schedule alarm %d in roughly %ld seconds\n", nextalarm, 00346 delta.tv_sec)); 00347 # endif /* SIGALRM */ 00348 # endif /* HAVE_SETITIMER */ 00349 #endif /* WIN32 */ 00350 00351 } else { 00352 DEBUGMSGTL(("snmp_alarm", "no alarms found to schedule\n")); 00353 } 00354 } 00355 00356 00388 unsigned int 00389 snmp_alarm_register(unsigned int when, unsigned int flags, 00390 SNMPAlarmCallback * thecallback, void *clientarg) 00391 { 00392 struct timeval t; 00393 00394 if (0 == when) { 00395 t.tv_sec = 0; 00396 t.tv_usec = 1; 00397 } else { 00398 t.tv_sec = when; 00399 t.tv_usec = 0; 00400 } 00401 00402 return snmp_alarm_register_hr(t, flags, thecallback, clientarg); 00403 } 00404 00405 00442 unsigned int 00443 snmp_alarm_register_hr(struct timeval t, unsigned int flags, 00444 SNMPAlarmCallback * cb, void *cd) 00445 { 00446 struct snmp_alarm **s = NULL; 00447 00448 for (s = &(thealarms); *s != NULL; s = &((*s)->next)); 00449 00450 *s = SNMP_MALLOC_STRUCT(snmp_alarm); 00451 if (*s == NULL) { 00452 return 0; 00453 } 00454 00455 (*s)->t.tv_sec = t.tv_sec; 00456 (*s)->t.tv_usec = t.tv_usec; 00457 (*s)->flags = flags; 00458 (*s)->clientarg = cd; 00459 (*s)->thecallback = cb; 00460 (*s)->clientreg = regnum++; 00461 (*s)->next = NULL; 00462 00463 sa_update_entry(*s); 00464 00465 DEBUGMSGTL(("snmp_alarm", 00466 "registered alarm %d, t = %ld.%03ld, flags=0x%02x\n", 00467 (*s)->clientreg, (*s)->t.tv_sec, ((*s)->t.tv_usec / 1000), 00468 (*s)->flags)); 00469 00470 if (start_alarms) { 00471 set_an_alarm(); 00472 } 00473 00474 return (*s)->clientreg; 00475 }