Logo
Home page Net-SNMP

Archive Search:

Require all words?

Site Search:
Google
Main Page | Modules | Data Structures | File List | Data Fields | Related Pages | Examples

snmp_alarm.c

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 }

Generated on Fri Dec 30 13:47:47 2005 for net-snmp by  doxygen 1.3.9.1

Valid CSS!


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.