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.tv_sec == 0 && a->t.tv_usec == 0) { 00093 DEBUGMSGTL(("snmp_alarm", 00094 "update_entry: illegal interval specified\n")); 00095 return; 00096 } 00097 00098 if (a->t_last.tv_sec == 0 && a->t_last.tv_usec == 0) { 00099 struct timeval t_now; 00100 /* 00101 * Never been called yet, call time `t' from now. 00102 */ 00103 gettimeofday(&t_now, NULL); 00104 00105 a->t_last.tv_sec = t_now.tv_sec; 00106 a->t_last.tv_usec = t_now.tv_usec; 00107 00108 a->t_next.tv_sec = t_now.tv_sec + a->t.tv_sec; 00109 a->t_next.tv_usec = t_now.tv_usec + a->t.tv_usec; 00110 00111 while (a->t_next.tv_usec >= 1000000) { 00112 a->t_next.tv_usec -= 1000000; 00113 a->t_next.tv_sec += 1; 00114 } 00115 } else if (a->t_next.tv_sec == 0 && a->t_next.tv_usec == 0) { 00116 /* 00117 * We've been called but not reset for the next call. 00118 */ 00119 if (a->flags & SA_REPEAT) { 00120 a->t_next.tv_sec = a->t_last.tv_sec + a->t.tv_sec; 00121 a->t_next.tv_usec = a->t_last.tv_usec + a->t.tv_usec; 00122 00123 while (a->t_next.tv_usec >= 1000000) { 00124 a->t_next.tv_usec -= 1000000; 00125 a->t_next.tv_sec += 1; 00126 } 00127 } else { 00128 /* 00129 * Single time call, remove it. 00130 */ 00131 snmp_alarm_unregister(a->clientreg); 00132 } 00133 } 00134 } 00135 00149 void 00150 snmp_alarm_unregister(unsigned int clientreg) 00151 { 00152 struct snmp_alarm *sa_ptr, **prevNext = &thealarms; 00153 00154 for (sa_ptr = thealarms; 00155 sa_ptr != NULL && sa_ptr->clientreg != clientreg; 00156 sa_ptr = sa_ptr->next) { 00157 prevNext = &(sa_ptr->next); 00158 } 00159 00160 if (sa_ptr != NULL) { 00161 *prevNext = sa_ptr->next; 00162 DEBUGMSGTL(("snmp_alarm", "unregistered alarm %d\n", 00163 sa_ptr->clientreg)); 00164 /* 00165 * Note: do not free the clientarg, its the clients responsibility 00166 */ 00167 free(sa_ptr); 00168 } else { 00169 DEBUGMSGTL(("snmp_alarm", "no alarm %d to unregister\n", clientreg)); 00170 } 00171 } 00172 00182 void 00183 snmp_alarm_unregister_all(void) 00184 { 00185 struct snmp_alarm *sa_ptr, *sa_tmp; 00186 00187 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_tmp) { 00188 sa_tmp = sa_ptr->next; 00189 free(sa_ptr); 00190 } 00191 DEBUGMSGTL(("snmp_alarm", "ALL alarms unregistered\n")); 00192 thealarms = NULL; 00193 } 00194 00195 struct snmp_alarm * 00196 sa_find_next(void) 00197 { 00198 struct snmp_alarm *a, *lowest = NULL; 00199 00200 for (a = thealarms; a != NULL; a = a->next) { 00201 if (lowest == NULL) { 00202 lowest = a; 00203 } else if (a->t_next.tv_sec == lowest->t_next.tv_sec) { 00204 if (a->t_next.tv_usec < lowest->t_next.tv_usec) { 00205 lowest = a; 00206 } 00207 } else if (a->t_next.tv_sec < lowest->t_next.tv_sec) { 00208 lowest = a; 00209 } 00210 } 00211 return lowest; 00212 } 00213 00214 struct snmp_alarm * 00215 sa_find_specific(unsigned int clientreg) 00216 { 00217 struct snmp_alarm *sa_ptr; 00218 for (sa_ptr = thealarms; sa_ptr != NULL; sa_ptr = sa_ptr->next) { 00219 if (sa_ptr->clientreg == clientreg) { 00220 return sa_ptr; 00221 } 00222 } 00223 return NULL; 00224 } 00225 00226 void 00227 run_alarms(void) 00228 { 00229 int done = 0; 00230 struct snmp_alarm *a = NULL; 00231 unsigned int clientreg; 00232 struct timeval t_now; 00233 00234 /* 00235 * Loop through everything we have repeatedly looking for the next thing to 00236 * call until all events are finally in the future again. 00237 */ 00238 00239 while (!done) { 00240 if ((a = sa_find_next()) == NULL) { 00241 return; 00242 } 00243 00244 gettimeofday(&t_now, NULL); 00245 00246 if ((a->t_next.tv_sec < t_now.tv_sec) || 00247 ((a->t_next.tv_sec == t_now.tv_sec) && 00248 (a->t_next.tv_usec < t_now.tv_usec))) { 00249 clientreg = a->clientreg; 00250 DEBUGMSGTL(("snmp_alarm", "run alarm %d\n", clientreg)); 00251 (*(a->thecallback)) (clientreg, a->clientarg); 00252 DEBUGMSGTL(("snmp_alarm", "alarm %d completed\n", clientreg)); 00253 00254 if ((a = sa_find_specific(clientreg)) != NULL) { 00255 a->t_last.tv_sec = t_now.tv_sec; 00256 a->t_last.tv_usec = t_now.tv_usec; 00257 a->t_next.tv_sec = 0; 00258 a->t_next.tv_usec = 0; 00259 sa_update_entry(a); 00260 } else { 00261 DEBUGMSGTL(("snmp_alarm", "alarm %d deleted itself\n", 00262 clientreg)); 00263 } 00264 } else { 00265 done = 1; 00266 } 00267 } 00268 } 00269 00270 00271 00272 RETSIGTYPE 00273 alarm_handler(int a) 00274 { 00275 run_alarms(); 00276 set_an_alarm(); 00277 } 00278 00279 00280 00281 int 00282 get_next_alarm_delay_time(struct timeval *delta) 00283 { 00284 struct snmp_alarm *sa_ptr; 00285 struct timeval t_diff, t_now; 00286 00287 sa_ptr = sa_find_next(); 00288 00289 if (sa_ptr) { 00290 gettimeofday(&t_now, 0); 00291 00292 if ((t_now.tv_sec > sa_ptr->t_next.tv_sec) || 00293 ((t_now.tv_sec == sa_ptr->t_next.tv_sec) && 00294 (t_now.tv_usec > sa_ptr->t_next.tv_usec))) { 00295 /* 00296 * Time has already passed. Return the smallest possible amount of 00297 * time. 00298 */ 00299 delta->tv_sec = 0; 00300 delta->tv_usec = 1; 00301 return sa_ptr->clientreg; 00302 } else { 00303 /* 00304 * Time is still in the future. 00305 */ 00306 t_diff.tv_sec = sa_ptr->t_next.tv_sec - t_now.tv_sec; 00307 t_diff.tv_usec = sa_ptr->t_next.tv_usec - t_now.tv_usec; 00308 00309 while (t_diff.tv_usec < 0) { 00310 t_diff.tv_sec -= 1; 00311 t_diff.tv_usec += 1000000; 00312 } 00313 00314 delta->tv_sec = t_diff.tv_sec; 00315 delta->tv_usec = t_diff.tv_usec; 00316 return sa_ptr->clientreg; 00317 } 00318 } 00319 00320 /* 00321 * Nothing Left. 00322 */ 00323 return 0; 00324 } 00325 00326 00327 void 00328 set_an_alarm(void) 00329 { 00330 struct timeval delta; 00331 int nextalarm = get_next_alarm_delay_time(&delta); 00332 00333 /* 00334 * We don't use signals if they asked us nicely not to. It's expected 00335 * they'll check the next alarm time and do their own calling of 00336 * run_alarms(). 00337 */ 00338 00339 if (nextalarm && !netsnmp_ds_get_boolean(NETSNMP_DS_LIBRARY_ID, 00340 NETSNMP_DS_LIB_ALARM_DONT_USE_SIG)) { 00341 #ifndef WIN32 00342 # ifdef HAVE_SETITIMER 00343 struct itimerval it; 00344 00345 it.it_value.tv_sec = delta.tv_sec; 00346 it.it_value.tv_usec = delta.tv_usec; 00347 it.it_interval.tv_sec = 0; 00348 it.it_interval.tv_usec = 0; 00349 00350 signal(SIGALRM, alarm_handler); 00351 setitimer(ITIMER_REAL, &it, NULL); 00352 DEBUGMSGTL(("snmp_alarm", "schedule alarm %d in %d.%03d seconds\n", 00353 nextalarm, delta.tv_sec, (delta.tv_usec / 1000))); 00354 # else /* HAVE_SETITIMER */ 00355 # ifdef SIGALRM 00356 signal(SIGALRM, alarm_handler); 00357 alarm(delta.tv_sec); 00358 DEBUGMSGTL(("snmp_alarm", 00359 "schedule alarm %d in roughly %d seconds\n", nextalarm, 00360 delta.tv_sec)); 00361 # endif /* SIGALRM */ 00362 # endif /* HAVE_SETITIMER */ 00363 #endif /* WIN32 */ 00364 00365 } else { 00366 DEBUGMSGTL(("snmp_alarm", "no alarms found to schedule\n")); 00367 } 00368 } 00369 00370 00402 unsigned int 00403 snmp_alarm_register(unsigned int when, unsigned int flags, 00404 SNMPAlarmCallback * thecallback, void *clientarg) 00405 { 00406 struct snmp_alarm **sa_pptr; 00407 if (thealarms != NULL) { 00408 for (sa_pptr = &thealarms; (*sa_pptr) != NULL; 00409 sa_pptr = &((*sa_pptr)->next)); 00410 } else { 00411 sa_pptr = &thealarms; 00412 } 00413 00414 *sa_pptr = SNMP_MALLOC_STRUCT(snmp_alarm); 00415 if (*sa_pptr == NULL) 00416 return 0; 00417 00418 (*sa_pptr)->t.tv_sec = when; 00419 (*sa_pptr)->t.tv_usec = 0; 00420 (*sa_pptr)->flags = flags; 00421 (*sa_pptr)->clientarg = clientarg; 00422 (*sa_pptr)->thecallback = thecallback; 00423 (*sa_pptr)->clientreg = regnum++; 00424 (*sa_pptr)->next = NULL; 00425 sa_update_entry(*sa_pptr); 00426 00427 DEBUGMSGTL(("snmp_alarm", 00428 "registered alarm %d, t = %d.%03d, flags=0x%02x\n", 00429 (*sa_pptr)->clientreg, (*sa_pptr)->t.tv_sec, 00430 ((*sa_pptr)->t.tv_usec / 1000), (*sa_pptr)->flags)); 00431 00432 if (start_alarms) 00433 set_an_alarm(); 00434 return (*sa_pptr)->clientreg; 00435 } 00436 00437 00474 unsigned int 00475 snmp_alarm_register_hr(struct timeval t, unsigned int flags, 00476 SNMPAlarmCallback * cb, void *cd) 00477 { 00478 struct snmp_alarm **s = NULL; 00479 00480 for (s = &(thealarms); *s != NULL; s = &((*s)->next)); 00481 00482 *s = SNMP_MALLOC_STRUCT(snmp_alarm); 00483 if (*s == NULL) { 00484 return 0; 00485 } 00486 00487 (*s)->t.tv_sec = t.tv_sec; 00488 (*s)->t.tv_usec = t.tv_usec; 00489 (*s)->flags = flags; 00490 (*s)->clientarg = cd; 00491 (*s)->thecallback = cb; 00492 (*s)->clientreg = regnum++; 00493 (*s)->next = NULL; 00494 00495 sa_update_entry(*s); 00496 00497 DEBUGMSGTL(("snmp_alarm", 00498 "registered alarm %d, t = %d.%03d, flags=0x%02x\n", 00499 (*s)->clientreg, (*s)->t.tv_sec, ((*s)->t.tv_usec / 1000), 00500 (*s)->flags)); 00501 00502 if (start_alarms) { 00503 set_an_alarm(); 00504 } 00505 00506 return (*s)->clientreg; 00507 }
1.3.9.1
Last modified: Thursday, 01-Mar-2007 16:20:05 PST
For questions regarding web content and site functionality, please write to the net-snmp-users mail list.