Icinga-core 1.4.0
next gen monitoring
base/events.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002  *
00003  * EVENTS.C - Timed event functions for Icinga
00004  *
00005  * Copyright (c) 1999-2010 Ethan Galstad (egalstad@nagios.org)
00006  * Copyright (c) 2009-2011 Nagios Core Development Team and Community Contributors
00007  * Copyright (c) 2009-2011 Icinga Development Team (http://www.icinga.org)
00008  *
00009  * License:
00010  *
00011  * This program is free software; you can redistribute it and/or modify
00012  * it under the terms of the GNU General Public License version 2 as
00013  * published by the Free Software Foundation.
00014  *
00015  * This program is distributed in the hope that it will be useful,
00016  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00018  * GNU General Public License for more details.
00019  *
00020  * You should have received a copy of the GNU General Public License
00021  * along with this program; if not, write to the Free Software
00022  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00023  *
00024  *****************************************************************************/
00025 
00026 #include "../include/config.h"
00027 #include "../include/common.h"
00028 #include "../include/downtime.h"
00029 #include "../include/comments.h"
00030 #include "../include/statusdata.h"
00031 #include "../include/icinga.h"
00032 #include "../include/broker.h"
00033 #include "../include/sretention.h"
00034 
00035 /* make sure gcc3 won't hit here */
00036 #ifndef GCCTOOOLD
00037 #include "../include/profiler.h"
00038 #endif
00039 
00040 extern char     *config_file;
00041 
00042 extern int      test_scheduling;
00043 
00044 extern time_t   program_start;
00045 extern time_t   event_start;
00046 extern time_t   last_command_check;
00047 
00048 extern int      sigshutdown;
00049 extern int      sigrestart;
00050 
00051 extern double   sleep_time;
00052 extern int      interval_length;
00053 extern int      service_inter_check_delay_method;
00054 extern int      host_inter_check_delay_method;
00055 extern int      service_interleave_factor_method;
00056 extern int      max_host_check_spread;
00057 extern int      max_service_check_spread;
00058 
00059 extern int      command_check_interval;
00060 extern int      check_reaper_interval;
00061 extern int      service_freshness_check_interval;
00062 extern int      host_freshness_check_interval;
00063 extern int      auto_rescheduling_interval;
00064 extern int      auto_rescheduling_window;
00065 
00066 extern int      check_external_commands;
00067 extern int      check_orphaned_services;
00068 extern int      check_orphaned_hosts;
00069 extern int      check_service_freshness;
00070 extern int      check_host_freshness;
00071 extern int      auto_reschedule_checks;
00072 
00073 extern int      retain_state_information;
00074 extern int      retention_update_interval;
00075 
00076 extern int      max_parallel_service_checks;
00077 extern int      currently_running_service_checks;
00078 
00079 extern int      aggregate_status_updates;
00080 extern int      status_update_interval;
00081 
00082 extern int      log_rotation_method;
00083 
00084 extern int      service_check_timeout;
00085 
00086 extern int      execute_service_checks;
00087 extern int      execute_host_checks;
00088 
00089 extern int      child_processes_fork_twice;
00090 
00091 extern int      time_change_threshold;
00092 
00093 /* make sure gcc3 won't hit here */
00094 #ifndef GCCTOOOLD
00095 extern int      event_profiling_enabled;
00096 #endif
00097 
00098 timed_event *event_list_low=NULL;
00099 timed_event *event_list_low_tail=NULL;
00100 timed_event *event_list_high=NULL;
00101 timed_event *event_list_high_tail=NULL;
00102 
00103 extern host     *host_list;
00104 extern service  *service_list;
00105 
00106 sched_info scheduling_info;
00107 
00108 
00109 
00110 /******************************************************************/
00111 /************ EVENT SCHEDULING/HANDLING FUNCTIONS *****************/
00112 /******************************************************************/
00113 
00114 /* initialize the event timing loop before we start monitoring */
00115 void init_timing_loop(void){
00116         host *temp_host=NULL;
00117         service *temp_service=NULL;
00118         time_t current_time=0L;
00119         unsigned long interval_to_use=0L;
00120         int total_interleave_blocks=0;
00121         int current_interleave_block=1;
00122         int interleave_block_index=0;
00123         int mult_factor=0;
00124         int is_valid_time=0;
00125         time_t next_valid_time=0L;
00126         int schedule_check=0;
00127         double max_inter_check_delay=0.0;
00128         struct timeval tv[9];
00129         double runtime[9];
00130 
00131 
00132         log_debug_info(DEBUGL_FUNCTIONS,0,"init_timing_loop() start\n");
00133 
00134         /* get the time right now */
00135         time(&current_time);
00136 
00137 
00138         /******** GET BASIC HOST/SERVICE INFO  ********/
00139 
00140         scheduling_info.total_services=0;
00141         scheduling_info.total_scheduled_services=0;
00142         scheduling_info.total_hosts=0;
00143         scheduling_info.total_scheduled_hosts=0;
00144         scheduling_info.average_services_per_host=0.0;
00145         scheduling_info.average_scheduled_services_per_host=0.0;
00146         scheduling_info.average_service_execution_time=0.0;
00147         scheduling_info.service_check_interval_total=0;
00148         scheduling_info.average_service_inter_check_delay=0.0;
00149         scheduling_info.host_check_interval_total=0;
00150         scheduling_info.average_host_inter_check_delay=0.0;
00151                 
00152         if(test_scheduling==TRUE)
00153                 gettimeofday(&tv[0],NULL);
00154 
00155         /* get info on service checks to be scheduled */
00156         for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
00157 
00158                 schedule_check=TRUE;
00159 
00160                 /* service has no check interval */
00161                 if(temp_service->check_interval==0)
00162                         schedule_check=FALSE;
00163 
00164                 /* active checks are disabled */
00165                 if(temp_service->checks_enabled==FALSE)
00166                         schedule_check=FALSE;
00167 
00168                 /* are there any valid times this service can be checked? */
00169                 is_valid_time=check_time_against_period(current_time,temp_service->check_period_ptr);
00170                 if(is_valid_time==ERROR){
00171                         get_next_valid_time(current_time,&next_valid_time,temp_service->check_period_ptr);
00172                         if(current_time==next_valid_time)
00173                                 schedule_check=FALSE;
00174                         }
00175 
00176                 if(schedule_check==TRUE){
00177 
00178                         scheduling_info.total_scheduled_services++;
00179 
00180                         /* used later in inter-check delay calculations */
00181                         scheduling_info.service_check_interval_total+=temp_service->check_interval;
00182 
00183                         /* calculate rolling average execution time (available from retained state information) */
00184                         scheduling_info.average_service_execution_time=(double)(((scheduling_info.average_service_execution_time*(scheduling_info.total_scheduled_services-1)) + temp_service->execution_time)/(double)scheduling_info.total_scheduled_services);
00185                         }
00186                 else{
00187                         temp_service->should_be_scheduled=FALSE;
00188 
00189                         log_debug_info(DEBUGL_EVENTS,1,"Service '%s' on host '%s' should not be scheduled.\n",temp_service->description,temp_service->host_name);
00190                         }
00191 
00192                 scheduling_info.total_services++;
00193                 }
00194 
00195         if(test_scheduling==TRUE)
00196                 gettimeofday(&tv[1],NULL);
00197 
00198         /* get info on host checks to be scheduled */
00199         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
00200 
00201                 schedule_check=TRUE;
00202 
00203                 /* host has no check interval */
00204                 if(temp_host->check_interval==0)
00205                         schedule_check=FALSE;
00206 
00207                 /* active checks are disabled */
00208                 if(temp_host->checks_enabled==FALSE)
00209                         schedule_check=FALSE;
00210 
00211                 /* are there any valid times this host can be checked? */
00212                 is_valid_time=check_time_against_period(current_time,temp_host->check_period_ptr);
00213                 if(is_valid_time==ERROR){
00214                         get_next_valid_time(current_time,&next_valid_time,temp_host->check_period_ptr);
00215                         if(current_time==next_valid_time)
00216                                 schedule_check=FALSE;
00217                         }
00218 
00219                 if(schedule_check==TRUE){
00220 
00221                         scheduling_info.total_scheduled_hosts++;
00222 
00223                         /* this is used later in inter-check delay calculations */
00224                         scheduling_info.host_check_interval_total+=temp_host->check_interval;
00225                         }
00226                 else{
00227                         temp_host->should_be_scheduled=FALSE;
00228 
00229                         log_debug_info(DEBUGL_EVENTS,1,"Host '%s' should not be scheduled.\n",temp_host->name);
00230                         }
00231 
00232                 scheduling_info.total_hosts++;
00233                 }
00234 
00235         if(test_scheduling==TRUE)
00236                 gettimeofday(&tv[2],NULL);
00237 
00238         scheduling_info.average_services_per_host=(double)((double)scheduling_info.total_services/(double)scheduling_info.total_hosts);
00239         scheduling_info.average_scheduled_services_per_host=(double)((double)scheduling_info.total_scheduled_services/(double)scheduling_info.total_hosts);
00240 
00241         /* adjust the check interval total to correspond to the interval length */
00242         scheduling_info.service_check_interval_total=(scheduling_info.service_check_interval_total*interval_length);
00243 
00244         /* calculate the average check interval for services */
00245         scheduling_info.average_service_check_interval=(double)((double)scheduling_info.service_check_interval_total/(double)scheduling_info.total_scheduled_services);
00246 
00247 
00248         /******** DETERMINE SERVICE SCHEDULING PARAMS  ********/
00249 
00250         log_debug_info(DEBUGL_EVENTS,2,"Determining service scheduling parameters...");
00251 
00252         /* default max service check spread (in minutes) */
00253         scheduling_info.max_service_check_spread=max_service_check_spread;
00254 
00255         /* how should we determine the service inter-check delay to use? */
00256         switch(service_inter_check_delay_method){
00257 
00258         case ICD_NONE:
00259 
00260                 /* don't spread checks out - useful for testing parallelization code */
00261                 scheduling_info.service_inter_check_delay=0.0;
00262                 break;
00263 
00264         case ICD_DUMB:
00265 
00266                 /* be dumb and just schedule checks 1 second apart */
00267                 scheduling_info.service_inter_check_delay=1.0;
00268                 break;
00269                 
00270         case ICD_USER:
00271 
00272                 /* the user specified a delay, so don't try to calculate one */
00273                 break;
00274 
00275         case ICD_SMART:
00276         default:
00277 
00278                 /* be smart and calculate the best delay to use to minimize local load... */
00279                 if(scheduling_info.total_scheduled_services>0 && scheduling_info.service_check_interval_total>0){
00280 
00281                         /* calculate the average inter check delay (in seconds) needed to evenly space the service checks out */
00282                         scheduling_info.average_service_inter_check_delay=(double)(scheduling_info.average_service_check_interval/(double)scheduling_info.total_scheduled_services);
00283 
00284                         /* set the global inter check delay value */
00285                         scheduling_info.service_inter_check_delay=scheduling_info.average_service_inter_check_delay;
00286 
00287                         /* calculate max inter check delay and see if we should use that instead */
00288                         max_inter_check_delay=(double)((scheduling_info.max_service_check_spread*60.0)/(double)scheduling_info.total_scheduled_services);
00289                         if(scheduling_info.service_inter_check_delay>max_inter_check_delay)
00290                                 scheduling_info.service_inter_check_delay=max_inter_check_delay;
00291                         }
00292                 else
00293                         scheduling_info.service_inter_check_delay=0.0;
00294 
00295                 log_debug_info(DEBUGL_EVENTS,1,"Total scheduled service checks:  %d\n",scheduling_info.total_scheduled_services);
00296                 log_debug_info(DEBUGL_EVENTS,1,"Average service check interval:  %0.2f sec\n",scheduling_info.average_service_check_interval);
00297                 log_debug_info(DEBUGL_EVENTS,1,"Service inter-check delay:       %0.2f sec\n",scheduling_info.service_inter_check_delay);
00298                 }
00299 
00300         /* how should we determine the service interleave factor? */
00301         switch(service_interleave_factor_method){
00302 
00303         case ILF_USER:
00304 
00305                 /* the user supplied a value, so don't do any calculation */
00306                 break;
00307 
00308         case ILF_SMART:
00309         default:
00310 
00311                 /* protect against a divide by zero problem - shouldn't happen, but just in case... */
00312                 if(scheduling_info.total_hosts==0)
00313                         scheduling_info.total_hosts=1;
00314 
00315                 scheduling_info.service_interleave_factor=(int)(ceil(scheduling_info.average_scheduled_services_per_host));
00316 
00317                 log_debug_info(DEBUGL_EVENTS,1,"Total scheduled service checks: %d\n",scheduling_info.total_scheduled_services);
00318                 log_debug_info(DEBUGL_EVENTS,1,"Total hosts:                    %d\n",scheduling_info.total_hosts);
00319                 log_debug_info(DEBUGL_EVENTS,1,"Service Interleave factor:      %d\n",scheduling_info.service_interleave_factor);
00320                 }
00321 
00322         /* calculate number of service interleave blocks */
00323         if(scheduling_info.service_interleave_factor==0)
00324                 total_interleave_blocks=scheduling_info.total_scheduled_services;
00325         else
00326                 total_interleave_blocks=(int)ceil((double)scheduling_info.total_scheduled_services/(double)scheduling_info.service_interleave_factor);
00327 
00328         scheduling_info.first_service_check=(time_t)0L;
00329         scheduling_info.last_service_check=(time_t)0L;
00330 
00331         log_debug_info(DEBUGL_EVENTS,1,"Total scheduled services: %d\n",scheduling_info.total_scheduled_services);
00332         log_debug_info(DEBUGL_EVENTS,1,"Service Interleave factor: %d\n",scheduling_info.service_interleave_factor);
00333         log_debug_info(DEBUGL_EVENTS,1,"Total service interleave blocks: %d\n",total_interleave_blocks);
00334         log_debug_info(DEBUGL_EVENTS,1,"Service inter-check delay: %2.1f\n",scheduling_info.service_inter_check_delay);
00335         
00336 
00337         if(test_scheduling==TRUE)
00338                 gettimeofday(&tv[3],NULL);
00339 
00340         /******** SCHEDULE SERVICE CHECKS  ********/
00341 
00342         log_debug_info(DEBUGL_EVENTS,2,"Scheduling service checks...");
00343 
00344         /* determine check times for service checks (with interleaving to minimize remote load) */
00345         current_interleave_block=0;
00346         for(temp_service=service_list;temp_service!=NULL && scheduling_info.service_interleave_factor>0;){
00347 
00348                 log_debug_info(DEBUGL_EVENTS,2,"Current Interleave Block: %d\n",current_interleave_block);
00349 
00350                 for(interleave_block_index=0;interleave_block_index<scheduling_info.service_interleave_factor && temp_service!=NULL;temp_service=temp_service->next){
00351 
00352                         log_debug_info(DEBUGL_EVENTS,2,"Service '%s' on host '%s'\n",temp_service->description,temp_service->host_name);
00353                         /* skip this service if it shouldn't be scheduled */
00354                         if(temp_service->should_be_scheduled==FALSE){
00355                                 log_debug_info(DEBUGL_EVENTS,2,"Service check should not be scheduled.\n");
00356                                 continue;
00357                                 }
00358 
00359                         /* skip services that are already scheduled for the future (from retention data), but reschedule ones that were supposed to happen while we weren't running... */
00360                         if(temp_service->next_check>current_time){
00361                                 log_debug_info(DEBUGL_EVENTS,2,"Service is already scheduled to be checked in the future: %s\n",ctime(&temp_service->next_check));
00362                                 continue;
00363                                 }
00364 
00365                         /* interleave block index should only be increased when we find a schedulable service */
00366                         /* moved from for() loop 11/05/05 EG */
00367                         interleave_block_index++;
00368 
00369                         mult_factor=current_interleave_block+(interleave_block_index*total_interleave_blocks);
00370 
00371                         log_debug_info(DEBUGL_EVENTS,2,"CIB: %d, IBI: %d, TIB: %d, SIF: %d\n",current_interleave_block,interleave_block_index,total_interleave_blocks,scheduling_info.service_interleave_factor);
00372                         log_debug_info(DEBUGL_EVENTS,2,"Mult factor: %d\n",mult_factor);
00373 
00374                         /* set the preferred next check time for the service */
00375                         temp_service->next_check=(time_t)(current_time+(mult_factor*scheduling_info.service_inter_check_delay));
00376 
00377                         log_debug_info(DEBUGL_EVENTS,2,"Preferred Check Time: %lu --> %s",(unsigned long)temp_service->next_check,ctime(&temp_service->next_check));
00378 
00379 
00380                         /* make sure the service can actually be scheduled when we want */
00381                         is_valid_time=check_time_against_period(temp_service->next_check,temp_service->check_period_ptr);
00382                         if(is_valid_time==ERROR){
00383                                 log_debug_info(DEBUGL_EVENTS,2,"Preferred Time is Invalid In Timeperiod '%s': %lu --> %s",temp_service->check_period_ptr->name,(unsigned long)temp_service->next_check,ctime(&temp_service->next_check));
00384                                 get_next_valid_time(temp_service->next_check,&next_valid_time,temp_service->check_period_ptr);
00385                                 temp_service->next_check=next_valid_time;
00386                                 }
00387 
00388                         log_debug_info(DEBUGL_EVENTS,2,"Actual Check Time: %lu --> %s",(unsigned long)temp_service->next_check,ctime(&temp_service->next_check));
00389 
00390                         if(scheduling_info.first_service_check==(time_t)0 || (temp_service->next_check<scheduling_info.first_service_check))
00391                                 scheduling_info.first_service_check=temp_service->next_check;
00392                         if(temp_service->next_check > scheduling_info.last_service_check)
00393                                 scheduling_info.last_service_check=temp_service->next_check;
00394                         }
00395 
00396                 current_interleave_block++;
00397                 }
00398 
00399         if(test_scheduling==TRUE)
00400                 gettimeofday(&tv[4],NULL);
00401 
00402         /* add scheduled service checks to event queue */
00403         for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
00404 
00405                 /* update status of all services (scheduled or not) */
00406                 update_service_status(temp_service,FALSE);
00407 
00408                 /* skip most services that shouldn't be scheduled */
00409                 if(temp_service->should_be_scheduled==FALSE){
00410 
00411                         /* passive checks are an exception if a forced check was scheduled before Icinga was restarted */
00412                         if(!(temp_service->checks_enabled==FALSE && temp_service->next_check!=(time_t)0L && (temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION)))
00413                                 continue;
00414                         }
00415 
00416                 /* create a new service check event */
00417                 schedule_new_event(EVENT_SERVICE_CHECK,FALSE,temp_service->next_check,FALSE,0,NULL,TRUE,(void *)temp_service,NULL,temp_service->check_options);
00418                 }
00419 
00420 
00421         if(test_scheduling==TRUE)
00422                 gettimeofday(&tv[5],NULL);
00423 
00424         /******** DETERMINE HOST SCHEDULING PARAMS  ********/
00425 
00426         log_debug_info(DEBUGL_EVENTS,2,"Determining host scheduling parameters...");
00427 
00428         scheduling_info.first_host_check=(time_t)0L;
00429         scheduling_info.last_host_check=(time_t)0L;
00430 
00431         /* default max host check spread (in minutes) */
00432         scheduling_info.max_host_check_spread=max_host_check_spread;
00433 
00434         /* how should we determine the host inter-check delay to use? */
00435         switch(host_inter_check_delay_method){
00436 
00437         case ICD_NONE:
00438 
00439                 /* don't spread checks out */
00440                 scheduling_info.host_inter_check_delay=0.0;
00441                 break;
00442 
00443         case ICD_DUMB:
00444 
00445                 /* be dumb and just schedule checks 1 second apart */
00446                 scheduling_info.host_inter_check_delay=1.0;
00447                 break;
00448 
00449         case ICD_USER:
00450 
00451                 /* the user specified a delay, so don't try to calculate one */
00452                 break;
00453 
00454         case ICD_SMART:
00455         default:
00456 
00457                 /* be smart and calculate the best delay to use to minimize local load... */
00458                 if(scheduling_info.total_scheduled_hosts>0 && scheduling_info.host_check_interval_total>0){
00459 
00460                         /* adjust the check interval total to correspond to the interval length */
00461                         scheduling_info.host_check_interval_total=(scheduling_info.host_check_interval_total*interval_length);
00462 
00463                         /* calculate the average check interval for hosts */
00464                         scheduling_info.average_host_check_interval=(double)((double)scheduling_info.host_check_interval_total/(double)scheduling_info.total_scheduled_hosts);
00465 
00466                         /* calculate the average inter check delay (in seconds) needed to evenly space the host checks out */
00467                         scheduling_info.average_host_inter_check_delay=(double)(scheduling_info.average_host_check_interval/(double)scheduling_info.total_scheduled_hosts);
00468 
00469                         /* set the global inter check delay value */
00470                         scheduling_info.host_inter_check_delay=scheduling_info.average_host_inter_check_delay;
00471 
00472                         /* calculate max inter check delay and see if we should use that instead */
00473                         max_inter_check_delay=(double)((scheduling_info.max_host_check_spread*60.0)/(double)scheduling_info.total_scheduled_hosts);
00474                         if(scheduling_info.host_inter_check_delay>max_inter_check_delay)
00475                                 scheduling_info.host_inter_check_delay=max_inter_check_delay;
00476                         }
00477                 else
00478                         scheduling_info.host_inter_check_delay=0.0;
00479 
00480                 log_debug_info(DEBUGL_EVENTS,2,"Total scheduled host checks:  %d\n",scheduling_info.total_scheduled_hosts);
00481                 log_debug_info(DEBUGL_EVENTS,2,"Host check interval total:    %lu\n",scheduling_info.host_check_interval_total);
00482                 log_debug_info(DEBUGL_EVENTS,2,"Average host check interval:  %0.2f sec\n",scheduling_info.average_host_check_interval);
00483                 log_debug_info(DEBUGL_EVENTS,2,"Host inter-check delay:       %0.2f sec\n",scheduling_info.host_inter_check_delay);
00484                 }
00485 
00486         if(test_scheduling==TRUE)
00487                 gettimeofday(&tv[6],NULL);
00488 
00489 
00490         /******** SCHEDULE HOST CHECKS  ********/
00491 
00492         log_debug_info(DEBUGL_EVENTS,2,"Scheduling host checks...");
00493 
00494         /* determine check times for host checks */
00495         mult_factor=0;
00496         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
00497 
00498                 log_debug_info(DEBUGL_EVENTS,2,"Host '%s'\n",temp_host->name);
00499 
00500                 /* skip hosts that shouldn't be scheduled */
00501                 if(temp_host->should_be_scheduled==FALSE){
00502                         log_debug_info(DEBUGL_EVENTS,2,"Host check should not be scheduled.\n");
00503                         continue;
00504                         }
00505 
00506                 /* skip hosts that are already scheduled for the future (from retention data), but reschedule ones that were supposed to be checked before we started */
00507                 if(temp_host->next_check>current_time){
00508                         log_debug_info(DEBUGL_EVENTS,2,"Host is already scheduled to be checked in the future: %s\n",ctime(&temp_host->next_check));
00509                         continue;
00510                         }
00511 
00512                 /* calculate preferred host check time */
00513                 temp_host->next_check=(time_t)(current_time+(mult_factor*scheduling_info.host_inter_check_delay));
00514 
00515                 log_debug_info(DEBUGL_EVENTS,2,"Preferred Check Time: %lu --> %s",(unsigned long)temp_host->next_check,ctime(&temp_host->next_check));
00516 
00517                 /* make sure the host can actually be scheduled at this time */
00518                 is_valid_time=check_time_against_period(temp_host->next_check,temp_host->check_period_ptr);
00519                 if(is_valid_time==ERROR){
00520                         get_next_valid_time(temp_host->next_check,&next_valid_time,temp_host->check_period_ptr);
00521                         temp_host->next_check=next_valid_time;
00522                         }
00523 
00524                 log_debug_info(DEBUGL_EVENTS,2,"Actual Check Time: %lu --> %s",(unsigned long)temp_host->next_check,ctime(&temp_host->next_check));
00525 
00526                 if(scheduling_info.first_host_check==(time_t)0 || (temp_host->next_check<scheduling_info.first_host_check))
00527                         scheduling_info.first_host_check=temp_host->next_check;
00528                 if(temp_host->next_check > scheduling_info.last_host_check)
00529                         scheduling_info.last_host_check=temp_host->next_check;
00530 
00531                 mult_factor++;
00532                 }
00533 
00534         if(test_scheduling==TRUE)
00535                 gettimeofday(&tv[7],NULL);
00536 
00537         /* add scheduled host checks to event queue */
00538         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
00539 
00540                 /* update status of all hosts (scheduled or not) */
00541                 update_host_status(temp_host,FALSE);
00542 
00543                 /* skip most hosts that shouldn't be scheduled */
00544                 if(temp_host->should_be_scheduled==FALSE){
00545 
00546                         /* passive checks are an exception if a forced check was scheduled before Icinga was restarted */
00547                         if(!(temp_host->checks_enabled==FALSE && temp_host->next_check!=(time_t)0L && (temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION)))
00548                                 continue;
00549                         }
00550 
00551                 /* schedule a new host check event */
00552                 schedule_new_event(EVENT_HOST_CHECK,FALSE,temp_host->next_check,FALSE,0,NULL,TRUE,(void *)temp_host,NULL,temp_host->check_options);
00553                 }
00554 
00555         if(test_scheduling==TRUE)
00556                 gettimeofday(&tv[8],NULL);
00557 
00558 
00559         /******** SCHEDULE MISC EVENTS ********/
00560 
00561         /* add a host and service check rescheduling event */
00562         if(auto_reschedule_checks==TRUE)
00563                 schedule_new_event(EVENT_RESCHEDULE_CHECKS,TRUE,current_time+auto_rescheduling_interval,TRUE,auto_rescheduling_interval,NULL,TRUE,NULL,NULL,0);
00564 
00565         /* add a check result reaper event */
00566         schedule_new_event(EVENT_CHECK_REAPER,TRUE,current_time+check_reaper_interval,TRUE,check_reaper_interval,NULL,TRUE,NULL,NULL,0);
00567 
00568         /* add an orphaned check event */
00569         if(check_orphaned_services==TRUE || check_orphaned_hosts==TRUE)
00570                 schedule_new_event(EVENT_ORPHAN_CHECK,TRUE,current_time+DEFAULT_ORPHAN_CHECK_INTERVAL,TRUE,DEFAULT_ORPHAN_CHECK_INTERVAL,NULL,TRUE,NULL,NULL,0);
00571 
00572         /* add a service result "freshness" check event */
00573         if(check_service_freshness==TRUE)
00574                 schedule_new_event(EVENT_SFRESHNESS_CHECK,TRUE,current_time+service_freshness_check_interval,TRUE,service_freshness_check_interval,NULL,TRUE,NULL,NULL,0);
00575 
00576         /* add a host result "freshness" check event */
00577         if(check_host_freshness==TRUE)
00578                 schedule_new_event(EVENT_HFRESHNESS_CHECK,TRUE,current_time+host_freshness_check_interval,TRUE,host_freshness_check_interval,NULL,TRUE,NULL,NULL,0);
00579 
00580         /* add a status save event */
00581         if(aggregate_status_updates==TRUE)
00582                 schedule_new_event(EVENT_STATUS_SAVE,TRUE,current_time+status_update_interval,TRUE,status_update_interval,NULL,TRUE,NULL,NULL,0);
00583 
00584         /* add an external command check event if needed */
00585         if(check_external_commands==TRUE){
00586                 if(command_check_interval==-1)
00587                         interval_to_use=(unsigned long)60;
00588                 else
00589                         interval_to_use=(unsigned long)command_check_interval;
00590                 schedule_new_event(EVENT_COMMAND_CHECK,TRUE,current_time+interval_to_use,TRUE,interval_to_use,NULL,TRUE,NULL,NULL,0);
00591                 }
00592 
00593         /* add a log rotation event if necessary */
00594         if(log_rotation_method!=LOG_ROTATION_NONE)
00595                 schedule_new_event(EVENT_LOG_ROTATION,TRUE,get_next_log_rotation_time(),TRUE,0,(void *)get_next_log_rotation_time,TRUE,NULL,NULL,0);
00596 
00597         /* add a retention data save event if needed */
00598         if(retain_state_information==TRUE && retention_update_interval>0)
00599                 schedule_new_event(EVENT_RETENTION_SAVE,TRUE,current_time+(retention_update_interval*60),TRUE,(retention_update_interval*60),NULL,TRUE,NULL,NULL,0);
00600 
00601         if(test_scheduling==TRUE){
00602 
00603                 runtime[0]=(double)((double)(tv[1].tv_sec-tv[0].tv_sec)+(double)((tv[1].tv_usec-tv[0].tv_usec)/1000.0)/1000.0);
00604                 runtime[1]=(double)((double)(tv[2].tv_sec-tv[1].tv_sec)+(double)((tv[2].tv_usec-tv[1].tv_usec)/1000.0)/1000.0);
00605                 runtime[2]=(double)((double)(tv[3].tv_sec-tv[2].tv_sec)+(double)((tv[3].tv_usec-tv[2].tv_usec)/1000.0)/1000.0);
00606                 runtime[3]=(double)((double)(tv[4].tv_sec-tv[3].tv_sec)+(double)((tv[4].tv_usec-tv[3].tv_usec)/1000.0)/1000.0);
00607                 runtime[4]=(double)((double)(tv[5].tv_sec-tv[4].tv_sec)+(double)((tv[5].tv_usec-tv[4].tv_usec)/1000.0)/1000.0);
00608                 runtime[5]=(double)((double)(tv[6].tv_sec-tv[5].tv_sec)+(double)((tv[6].tv_usec-tv[5].tv_usec)/1000.0)/1000.0);
00609                 runtime[6]=(double)((double)(tv[7].tv_sec-tv[6].tv_sec)+(double)((tv[7].tv_usec-tv[6].tv_usec)/1000.0)/1000.0);
00610                 runtime[7]=(double)((double)(tv[8].tv_sec-tv[7].tv_sec)+(double)((tv[8].tv_usec-tv[7].tv_usec)/1000.0)/1000.0);
00611 
00612                 runtime[8]=(double)((double)(tv[8].tv_sec-tv[0].tv_sec)+(double)((tv[8].tv_usec-tv[0].tv_usec)/1000.0)/1000.0);
00613 
00614                 printf("EVENT SCHEDULING TIMES\n");
00615                 printf("-------------------------------------\n");
00616                 printf("Get service info:        %.6lf sec\n",runtime[0]);
00617                 printf("Get host info info:      %.6lf sec\n",runtime[1]);
00618                 printf("Get service params:      %.6lf sec\n",runtime[2]);
00619                 printf("Schedule service times:  %.6lf sec\n",runtime[3]);
00620                 printf("Schedule service events: %.6lf sec\n",runtime[4]);
00621                 printf("Get host params:         %.6lf sec\n",runtime[5]);
00622                 printf("Schedule host times:     %.6lf sec\n",runtime[6]);
00623                 printf("Schedule host events:    %.6lf sec\n",runtime[7]);
00624                 printf("                         ============\n");
00625                 printf("TOTAL:                   %.6lf sec\n",runtime[8]);
00626                 printf("\n\n");
00627                 }
00628 
00629         log_debug_info(DEBUGL_FUNCTIONS,0,"init_timing_loop() end\n");
00630 
00631         return;
00632         }
00633 
00634 
00635 /*gives information about a particular event*/
00636 void display_event_data(timed_event* event, int priority){
00637 
00638         service *temp_service=NULL;
00639         host *temp_host=NULL;
00640 
00641         printf("\t\tEvent:");
00642 
00643         switch(event->event_type){
00644 
00645         case EVENT_SERVICE_CHECK:
00646                 printf("\t\t(service check)\n");
00647                 temp_service=(service *)event->event_data;
00648                 printf("\t\tService Description: %s\n",temp_service->description);
00649                 printf("\t\tAssociated Host:     %s\n",temp_service->host_name);
00650         break;
00651 
00652         case EVENT_HOST_CHECK:
00653                 printf("\t\t(host check)\n");
00654                 temp_host=(host *)event->event_data;
00655                 printf("\t\tHost:     %s\n",temp_host->name);
00656                 /* run a host check */
00657         break;
00658 
00659         case EVENT_COMMAND_CHECK:
00660                 printf("\t\t(external command check)\n");
00661         break;
00662 
00663         case EVENT_LOG_ROTATION:
00664                 printf("\t\t(log file rotation)\n");
00665         break;
00666 
00667         case EVENT_PROGRAM_SHUTDOWN:
00668                 printf("\t\t(program shutdown)\n");
00669         break;
00670 
00671         case EVENT_PROGRAM_RESTART:
00672                 printf("\t\t(program restart)\n");
00673         break;
00674 
00675         case EVENT_CHECK_REAPER:
00676                 printf("\t\t(service check reaper)\n");
00677         break;
00678 
00679         case EVENT_ORPHAN_CHECK:
00680                 printf("\t\t(orphaned service check)\n");
00681         break;
00682 
00683         case EVENT_RETENTION_SAVE:
00684                 printf("\t\t(retention save)\n");
00685         break;
00686 
00687         case EVENT_STATUS_SAVE:
00688                 printf("\t\t(status save)\n");
00689         break;
00690 
00691         case EVENT_SCHEDULED_DOWNTIME:
00692                 printf("\t\t(scheduled downtime)\n");
00693         break;
00694 
00695         case EVENT_SFRESHNESS_CHECK:
00696                 printf("\t\t(service result freshness check)\n");
00697         break;
00698 
00699         case EVENT_HFRESHNESS_CHECK:
00700                 printf("\t\t(host result freshness check)\n");
00701         break;
00702 
00703         case EVENT_EXPIRE_DOWNTIME:
00704                 printf("\t\t(expire downtime)\n");
00705         break;
00706 
00707         case EVENT_RESCHEDULE_CHECKS:
00708                 printf("\t\t(reschedule checks)\n");
00709         break;
00710 
00711         case EVENT_EXPIRE_COMMENT:
00712                 printf("\t\t(expire comment)\n");
00713         break;
00714 
00715         case EVENT_USER_FUNCTION:
00716                 printf("\t\t(user function)\n");
00717         break;
00718 
00719         default:
00720                 printf("\t\t(Unknown!!!)\n");
00721         break;
00722 
00723         }
00724 
00725         printf("\t\tPriority %s\n", (priority == 0 ?"Low":"High"));
00726         printf("\t\tInterval: %lu\n",event->event_interval);
00727         printf("\t\tEvent Time: %s\n",ctime(&event->run_time));
00728         printf("\n\n");
00729 }
00730 
00731 
00732 /* displays the service check scheduling queue */
00733 void display_schedule(void){
00734         timed_event* high_event=NULL;
00735         timed_event* low_event=NULL;
00736         timed_event* event=NULL;
00737         int priority=0;
00738     
00739         printf("*** The current scheduling queue is listed below ***\n");
00740 
00741         high_event = event_list_high;
00742         low_event = event_list_low;
00743 
00744         while(high_event || low_event){
00745                 if(low_event && high_event){
00746                         if(low_event->run_time < high_event->run_time){
00747                                 event = low_event;
00748                                 low_event = low_event->next;
00749                                 priority = 0;
00750                         }else{
00751                                 event = high_event;
00752                                 high_event = high_event->next;
00753                                 priority = 1;
00754                         }
00755                 }else{
00756                         if(high_event){
00757                                 event = high_event;
00758                                 high_event = high_event->next;
00759                                 priority = 1;
00760                         }
00761 
00762                         if(low_event){
00763                                 event = low_event;
00764                                 low_event = low_event->next;
00765                                 priority = 0;
00766                         }
00767                 }
00768 
00769                 display_event_data(event, priority);
00770         }
00771 }
00772 
00773 
00774 /* displays service check scheduling information */
00775 void display_scheduling_info(void){
00776         float minimum_concurrent_checks1=0.0;
00777         float minimum_concurrent_checks2=0.0;
00778         float minimum_concurrent_checks=0.0;
00779         float max_reaper_interval=0.0;
00780         int suggestions=0;
00781 
00782         printf("Projected scheduling information for host and service checks\n");
00783         printf("is listed below.  This information assumes that you are going\n");
00784         printf("to start running %s with your current config files.\n\n", PROGRAM_NAME);
00785 
00786         printf("HOST SCHEDULING INFORMATION\n");
00787         printf("---------------------------\n");
00788         printf("Total hosts:                     %d\n",scheduling_info.total_hosts);
00789         printf("Total scheduled hosts:           %d\n",scheduling_info.total_scheduled_hosts);
00790 
00791         printf("Host inter-check delay method:   ");
00792         if(host_inter_check_delay_method==ICD_NONE)
00793                 printf("NONE\n");
00794         else if(host_inter_check_delay_method==ICD_DUMB)
00795                 printf("DUMB\n");
00796         else if(host_inter_check_delay_method==ICD_SMART){
00797                 printf("SMART\n");
00798                 printf("Average host check interval:     %.2f sec\n",scheduling_info.average_host_check_interval);
00799                 }
00800         else
00801                 printf("USER-SUPPLIED VALUE\n");
00802         printf("Host inter-check delay:          %.2f sec\n",scheduling_info.host_inter_check_delay);
00803         printf("Max host check spread:           %d min\n",scheduling_info.max_host_check_spread);
00804         printf("First scheduled check:           %s",(scheduling_info.total_scheduled_hosts==0)?"N/A\n":ctime(&scheduling_info.first_host_check));
00805         printf("Last scheduled check:            %s",(scheduling_info.total_scheduled_hosts==0)?"N/A\n":ctime(&scheduling_info.last_host_check));
00806         printf("\n\n");
00807 
00808         printf("SERVICE SCHEDULING INFORMATION\n");
00809         printf("-------------------------------\n");
00810         printf("Total services:                     %d\n",scheduling_info.total_services);
00811         printf("Total scheduled services:           %d\n",scheduling_info.total_scheduled_services);
00812 
00813         printf("Service inter-check delay method:   ");
00814         if(service_inter_check_delay_method==ICD_NONE)
00815                 printf("NONE\n");
00816         else if(service_inter_check_delay_method==ICD_DUMB)
00817                 printf("DUMB\n");
00818         else if(service_inter_check_delay_method==ICD_SMART){
00819                 printf("SMART\n");
00820                 printf("Average service check interval:     %.2f sec\n",scheduling_info.average_service_check_interval);
00821                 }
00822         else
00823                 printf("USER-SUPPLIED VALUE\n");
00824         printf("Inter-check delay:                  %.2f sec\n",scheduling_info.service_inter_check_delay);
00825 
00826         printf("Interleave factor method:           %s\n",(service_interleave_factor_method==ILF_USER)?"USER-SUPPLIED VALUE":"SMART");
00827         if(service_interleave_factor_method==ILF_SMART)
00828                 printf("Average services per host:          %.2f\n",scheduling_info.average_services_per_host);
00829         printf("Service interleave factor:          %d\n",scheduling_info.service_interleave_factor);
00830 
00831         printf("Max service check spread:           %d min\n",scheduling_info.max_service_check_spread);
00832         printf("First scheduled check:              %s",ctime(&scheduling_info.first_service_check));
00833         printf("Last scheduled check:               %s",ctime(&scheduling_info.last_service_check));
00834         printf("\n\n");
00835 
00836         printf("CHECK PROCESSING INFORMATION\n");
00837         printf("----------------------------\n");
00838         printf("Check result reaper interval:       %d sec\n",check_reaper_interval);
00839         printf("Max concurrent service checks:      ");
00840         if(max_parallel_service_checks==0)
00841                 printf("Unlimited\n");
00842         else
00843                 printf("%d\n",max_parallel_service_checks);
00844         printf("\n\n");
00845 
00846         printf("PERFORMANCE SUGGESTIONS\n");
00847         printf("-----------------------\n");
00848 
00849 
00850         /***** MAX REAPER INTERVAL RECOMMENDATION *****/
00851 
00852         /* assume a 100% (2x) check burst for check reaper */
00853         /* assume we want a max of 2k files in the result queue at any given time */
00854         max_reaper_interval=floor(2000*scheduling_info.service_inter_check_delay);
00855         if(max_reaper_interval<2.0)
00856                 max_reaper_interval=2.0;
00857         if(max_reaper_interval>30.0)
00858                 max_reaper_interval=30.0;
00859         if((int)max_reaper_interval<check_reaper_interval){
00860                 printf("* Value for 'check_result_reaper_frequency' should be <= %d seconds\n",(int)max_reaper_interval);
00861                 suggestions++;
00862                 }
00863         if(check_reaper_interval<2){
00864                 printf("* Value for 'check_result_reaper_frequency' should be >= 2 seconds\n");
00865                 suggestions++;
00866                 }
00867 
00868         /***** MINIMUM CONCURRENT CHECKS RECOMMENDATION *****/
00869 
00870         /* first method (old) - assume a 100% (2x) service check burst for max concurrent checks */
00871         if(scheduling_info.service_inter_check_delay==0.0)
00872                 minimum_concurrent_checks1=ceil(check_reaper_interval*2.0);
00873         else
00874                 minimum_concurrent_checks1=ceil((check_reaper_interval*2.0)/scheduling_info.service_inter_check_delay);
00875 
00876         /* second method (new) - assume a 25% (1.25x) service check burst for max concurrent checks */
00877         minimum_concurrent_checks2=ceil((((double)scheduling_info.total_scheduled_services)/scheduling_info.average_service_check_interval) * 1.25 * check_reaper_interval * scheduling_info.average_service_execution_time);
00878 
00879         /* use max of computed values */
00880         if(minimum_concurrent_checks1>minimum_concurrent_checks2)
00881                 minimum_concurrent_checks=minimum_concurrent_checks1;
00882         else
00883                 minimum_concurrent_checks=minimum_concurrent_checks2;
00884 
00885         /* compare with configured value */
00886         if(((int)minimum_concurrent_checks > max_parallel_service_checks) && max_parallel_service_checks!=0){
00887                 printf("* Value for 'max_concurrent_checks' option should be >= %d\n",(int)minimum_concurrent_checks);
00888                 suggestions++;
00889                 }
00890 
00891         if(suggestions==0)
00892                 printf("I have no suggestions - things look okay.\n");
00893 
00894         printf("\n");
00895 
00896         return;
00897         }
00898 
00899 
00900 /* schedule a new timed event */
00901 int schedule_new_event(int event_type, int high_priority, time_t run_time, int recurring, unsigned long event_interval, void *timing_func, int compensate_for_time_change, void *event_data, void *event_args, int event_options){
00902         timed_event **event_list=NULL;
00903         timed_event **event_list_tail=NULL;
00904         timed_event *new_event=NULL;
00905 
00906         log_debug_info(DEBUGL_FUNCTIONS,0,"schedule_new_event()\n");
00907 
00908         if(high_priority==TRUE){
00909                 event_list=&event_list_high;
00910                 event_list_tail=&event_list_high_tail;
00911                 }
00912         else{
00913                 event_list=&event_list_low;
00914                 event_list_tail=&event_list_low_tail;
00915                 }
00916 
00917         new_event=(timed_event *)malloc(sizeof(timed_event));
00918         if(new_event!=NULL){
00919                 new_event->event_type=event_type;
00920                 new_event->event_data=event_data;
00921                 new_event->event_args=event_args;
00922                 new_event->event_options=event_options;
00923                 new_event->run_time=run_time;
00924                 new_event->recurring=recurring;
00925                 new_event->event_interval=event_interval;
00926                 new_event->timing_func=timing_func;
00927                 new_event->compensate_for_time_change=compensate_for_time_change;
00928                 }
00929         else
00930                 return ERROR;
00931 
00932         /* add the event to the event list */
00933         add_event(new_event,event_list,event_list_tail);
00934 
00935         return OK;
00936         }
00937 
00938 
00939 /* reschedule an event in order of execution time */
00940 void reschedule_event(timed_event *event, timed_event **event_list, timed_event **event_list_tail){
00941         time_t current_time=0L;
00942         time_t (*timingfunc)(void);
00943 
00944         log_debug_info(DEBUGL_FUNCTIONS,0,"reschedule_event()\n");
00945 
00946         /* reschedule recurring events... */
00947         if(event->recurring==TRUE){
00948 
00949                 /* use custom timing function */
00950                 if(event->timing_func!=NULL){
00951                         timingfunc=event->timing_func;
00952                         event->run_time=(*timingfunc)();
00953                         }
00954 
00955                 /* normal recurring events */
00956                 else{
00957                         event->run_time=event->run_time+event->event_interval;
00958                         time(&current_time);
00959                         if(event->run_time<current_time)
00960                                 event->run_time=current_time;
00961                         }
00962                 }
00963 
00964         /* add the event to the event list */
00965         add_event(event,event_list,event_list_tail);
00966 
00967         return;
00968         }
00969 
00970 
00971 /* add an event to list ordered by execution time */
00972 void add_event(timed_event *event, timed_event **event_list, timed_event **event_list_tail){
00973         timed_event *temp_event=NULL;
00974         timed_event *first_event=NULL;
00975 
00976         log_debug_info(DEBUGL_FUNCTIONS,0,"add_event()\n");
00977 
00978         event->next=NULL;
00979         event->prev=NULL;
00980 
00981         first_event=*event_list;
00982 
00983         /* add the event to the head of the list if there are no other events */
00984         if(*event_list==NULL){
00985                 *event_list=event;
00986                 *event_list_tail=event;
00987                 }
00988 
00989         /* add event to head of the list if it should be executed first */
00990         else if(event->run_time < first_event->run_time){
00991                 event->prev=NULL;
00992                 (*event_list)->prev=event;
00993                 event->next=*event_list;
00994                 *event_list=event;
00995                 }
00996 
00997         /* else place the event according to next execution time */
00998         else{
00999 
01000                 /* start from the end of the list, as new events are likely to be executed in the future, rather than now... */
01001                 for(temp_event=*event_list_tail;temp_event!=NULL;temp_event=temp_event->prev){
01002                         if(event->run_time >= temp_event->run_time){
01003                                 event->next=temp_event->next;
01004                                 event->prev=temp_event;
01005                                 temp_event->next=event;
01006                                 if(event->next==NULL)
01007                                         *event_list_tail=event;
01008                                 else
01009                                         event->next->prev=event;
01010                                 break;
01011                                 }
01012                         else if(temp_event->prev==NULL){
01013                                 temp_event->prev=event;
01014                                 event->next=temp_event;
01015                                 *event_list=event;
01016                                 break;
01017                                 }
01018                         }
01019                 }
01020 
01021 #ifdef USE_EVENT_BROKER
01022         /* send event data to broker */
01023         broker_timed_event(NEBTYPE_TIMEDEVENT_ADD,NEBFLAG_NONE,NEBATTR_NONE,event,NULL);
01024 #endif
01025 
01026         return;
01027         }
01028 
01029 
01030 
01031 /* remove an event from the queue */
01032 void remove_event(timed_event *event, timed_event **event_list, timed_event **event_list_tail){
01033         timed_event *temp_event=NULL;
01034 
01035         log_debug_info(DEBUGL_FUNCTIONS,0,"remove_event()\n");
01036 
01037 #ifdef USE_EVENT_BROKER
01038         /* send event data to broker */
01039         broker_timed_event(NEBTYPE_TIMEDEVENT_REMOVE,NEBFLAG_NONE,NEBATTR_NONE,event,NULL);
01040 #endif
01041 
01042         if(*event_list==NULL)
01043                 return;
01044 
01045         if(*event_list==event){
01046                 event->prev=NULL;
01047                 *event_list=event->next;
01048                 if(*event_list==NULL)
01049                         *event_list_tail=NULL;
01050                 }
01051 
01052         else{
01053 
01054                 for(temp_event=*event_list;temp_event!=NULL;temp_event=temp_event->next){
01055                         if(temp_event->next==event){
01056                                 temp_event->next=temp_event->next->next;
01057                                 if(temp_event->next==NULL)
01058                                         *event_list_tail=temp_event;
01059                                 else
01060                                         temp_event->next->prev=temp_event;
01061                                 event->next=NULL;
01062                                 event->prev=NULL;
01063                                 break;
01064                                 }
01065                         }
01066                 }
01067 
01068 
01069         return;
01070         }
01071 
01072 
01073 
01074 /* this is the main event handler loop */
01075 int event_execution_loop(void){
01076         timed_event *temp_event=NULL;
01077         timed_event sleep_event;
01078         time_t last_time=0L;
01079         time_t current_time=0L;
01080         time_t last_status_update=0L;
01081         int run_event=TRUE;
01082         int nudge_seconds;
01083         host *temp_host=NULL;
01084         service *temp_service=NULL;
01085         struct timespec delay;
01086         pid_t wait_result;
01087 
01088 /* make sure gcc3 won't hit here */
01089 #ifndef GCCTOOOLD
01090         struct timeval start;
01091 #endif
01092 
01093         log_debug_info(DEBUGL_FUNCTIONS,0,"event_execution_loop() start\n");
01094 
01095         time(&last_time);
01096 
01097         /* initialize fake "sleep" event */
01098         sleep_event.event_type=EVENT_SLEEP;
01099         sleep_event.run_time=last_time;
01100         sleep_event.recurring=FALSE;
01101         sleep_event.event_interval=0L;
01102         sleep_event.compensate_for_time_change=FALSE;
01103         sleep_event.timing_func=NULL;
01104         sleep_event.event_data=NULL;
01105         sleep_event.event_args=NULL;
01106         sleep_event.event_options=0;
01107         sleep_event.next=NULL;
01108         sleep_event.prev=NULL;
01109 
01110         while(1){
01111 
01112 /* make sure gcc3 won't hit here */
01113 #ifndef GCCTOOOLD
01114                 if(event_profiling_enabled)
01115                         gettimeofday(&start,NULL);
01116 #endif
01117 
01118                 /* see if we should exit or restart (a signal was encountered) */
01119                 if(sigshutdown==TRUE || sigrestart==TRUE)
01120                         break;
01121 
01122                 /* if we don't have any events to handle, exit */
01123                 if(event_list_high==NULL && event_list_low==NULL){
01124                         log_debug_info(DEBUGL_EVENTS,0,"There aren't any events that need to be handled! Exiting...\n");
01125                         break;
01126                         }
01127 
01128                 /* get the current time */
01129                 time(&current_time);
01130 
01131                 /* hey, wait a second...  we traveled back in time! */
01132                 if(current_time<last_time)
01133                         compensate_for_system_time_change((unsigned long)last_time,(unsigned long)current_time);
01134 
01135                 /* else if the time advanced over the specified threshold, try and compensate... */
01136                 else if((current_time-last_time)>=time_change_threshold)
01137                         compensate_for_system_time_change((unsigned long)last_time,(unsigned long)current_time);
01138 
01139                 /* keep track of the last time */
01140                 last_time=current_time;
01141 
01142                 log_debug_info(DEBUGL_EVENTS,1,"** Event Check Loop\n");
01143                 if(event_list_high!=NULL)
01144                         log_debug_info(DEBUGL_EVENTS,1,"Next High Priority Event Time: %s",ctime(&event_list_high->run_time));
01145                 else
01146                         log_debug_info(DEBUGL_EVENTS,1,"No high priority events are scheduled...\n");
01147                 if(event_list_low!=NULL)
01148                         log_debug_info(DEBUGL_EVENTS,1,"Next Low Priority Event Time:  %s",ctime(&event_list_low->run_time));
01149                 else
01150                         log_debug_info(DEBUGL_EVENTS,1,"No low priority events are scheduled...\n");
01151                 log_debug_info(DEBUGL_EVENTS,1,"Current/Max Service Checks: %d/%d\n",currently_running_service_checks,max_parallel_service_checks);
01152 
01153                 /* get rid of terminated child processes (zombies) */
01154                 if(child_processes_fork_twice==FALSE){
01155                         while((wait_result=waitpid(-1,NULL,WNOHANG))>0);
01156                         }
01157 
01158                 /* handle high priority events */
01159                 if(event_list_high!=NULL && (current_time>=event_list_high->run_time)){
01160 
01161                         /* remove the first event from the timing loop */
01162                         temp_event=event_list_high;
01163                         event_list_high=event_list_high->next;
01164 
01165                         /* we may have just removed the only item from the list */
01166                         if (event_list_high!=NULL)
01167                                 event_list_high->prev=NULL;
01168 
01169                         /* handle the event */
01170                         handle_timed_event(temp_event);
01171 
01172                         /* reschedule the event if necessary */
01173                         if(temp_event->recurring==TRUE)
01174                                 reschedule_event(temp_event,&event_list_high,&event_list_high_tail);
01175 
01176                         /* else free memory associated with the event */
01177                         else
01178                                 my_free(temp_event);
01179                         }
01180 
01181                 /* 21-09-2010 NOTE MF:
01182                         The logic on low priority events just as host and service checks work liks this:
01183                         Set run_event=TRUE on looping start, check if next event is a serviecheck. If matched,
01184                         check for several things, most important for disabled checks. If those are disabled,
01185                         set run_event=FALSE (this flag will be checked at the end). The servicecheck event
01186                         will be removed from the eventlist.
01187                         Same goes for the hostcheck events, and afterwards, run_event is checked and no matter
01188                         if service or host check event, it gets executed as a timed event, if run_event==TRUE.
01189 
01190                         Previous code (21-09-2010) had a logical AND operation, servicecheck and hostcheck events
01191                         could have been tested within one looping. If servicecheck was disabled, run_event=FALSE,
01192                         and removed from event queue resulted in next event = hostcheck, which was matched by the
01193                         2nd IF - also having run_event set to FALSE, causing the hostcheck being skipped too.
01194                         By changing this to a logical OR operation, IF ... ELSE IF ..., only one check can be
01195                         matched throughout a single looping and run_event is responsible for only one event at a
01196                         time - service OR host check event.
01197                 */
01198 
01199                 /* handle low priority events */
01200                 else if(event_list_low!=NULL && (current_time>=event_list_low->run_time)){
01201 
01202                         /* default action is to execute the event */
01203                         run_event=TRUE;
01204                         nudge_seconds=0;
01205 
01206                         /* run a few checks before executing a service check... */
01207                         if(event_list_low->event_type==EVENT_SERVICE_CHECK){
01208 
01209                                 temp_service=(service *)event_list_low->event_data;
01210 
01211                                 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Run a few checks before executing a service check for '%s'.\n", temp_service->description);
01212 
01213                                 /* don't run a service check if we're already maxed out on the number of parallel service checks...  */
01214                                 if(max_parallel_service_checks!=0 && (currently_running_service_checks >= max_parallel_service_checks)){
01215 
01216                                         /* Move it at least 5 seconds (to overcome the current peak), with a random 10 seconds (to spread the load) */
01217                                         nudge_seconds=5+(rand() % 10);
01218                                         log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,0,"**WARNING** Max concurrent service checks (%d) has been reached!  Nudging %s:%s by %d seconds...\n",max_parallel_service_checks, temp_service->host_name, temp_service->description, nudge_seconds);
01219 
01220                                         logit(NSLOG_RUNTIME_WARNING,TRUE,"\tMax concurrent service checks (%d) has been reached.  Nudging %s:%s by %d seconds...\n",max_parallel_service_checks, temp_service->host_name, temp_service->description, nudge_seconds);
01221                                         run_event=FALSE;
01222                                         }
01223 
01224                                 /* don't run a service check if active checks are disabled */
01225                                 if(execute_service_checks==FALSE){
01226 
01227                                         log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"We're not executing service checks right now, so we'll skip this event.\n");
01228 
01229                                         run_event=FALSE;
01230                                         }
01231 
01232                                 /* forced checks override normal check logic */
01233                                 if((temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION))
01234                                         run_event=TRUE;
01235 
01236                                 /* reschedule the check if we can't run it now */
01237                                 if(run_event==FALSE){
01238 
01239                                         /* remove the service check from the event queue and reschedule it for a later time */
01240                                         /* 12/20/05 since event was not executed, it needs to be remove()'ed to maintain sync with event broker modules */
01241                                         log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Skip event, removing service '%s' from list.\n", temp_service->description);
01242                                         temp_event=event_list_low;
01243                                         remove_event(temp_event,&event_list_low,&event_list_low_tail);
01244                                         /*
01245                                         event_list_low=event_list_low->next;
01246                                         */
01247                                         if(nudge_seconds) {
01248                                                 /* We nudge the next check time when it is due to too many concurrent service checks */
01249                                                 temp_service->next_check=(time_t)(temp_service->next_check+nudge_seconds);
01250                                                 }
01251                                         else {
01252                                                 /* Otherwise reschedule (TODO: This should be smarter as it doesn't consider its timeperiod) */
01253                                                 if(temp_service->state_type==SOFT_STATE && temp_service->current_state!=STATE_OK)
01254                                                         temp_service->next_check=(time_t)(temp_service->next_check+(temp_service->retry_interval*interval_length));
01255                                                 else
01256                                                         temp_service->next_check=(time_t)(temp_service->next_check+(temp_service->check_interval*interval_length));
01257                                                 }
01258 
01259                                         temp_event->run_time=temp_service->next_check;
01260                                         reschedule_event(temp_event,&event_list_low,&event_list_low_tail);
01261                                         update_service_status(temp_service,FALSE);
01262 
01263                                         run_event=FALSE;
01264                                         }
01265 
01266                                 }
01267 
01268                         /* run a few checks before executing a host check... */
01269                         else if(event_list_low->event_type==EVENT_HOST_CHECK){
01270 
01271                                 temp_host=(host *)event_list_low->event_data;
01272 
01273                                 log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Run a few checks before executing a host check for '%s'.\n", temp_host->name);
01274 
01275                                 /* don't run a host check if active checks are disabled */
01276                                 if(execute_host_checks==FALSE){
01277 
01278                                         log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"We're not executing host checks right now, so we'll skip this event.\n");
01279 
01280                                         run_event=FALSE;
01281                                         }
01282 
01283                                 /* forced checks override normal check logic */
01284                                 if((temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION))
01285                                         run_event=TRUE;
01286 
01287                                 /* reschedule the host check if we can't run it right now */
01288                                 if(run_event==FALSE){
01289 
01290                                         /* remove the host check from the event queue and reschedule it for a later time */
01291                                         /* 12/20/05 since event was not executed, it needs to be remove()'ed to maintain sync with event broker modules */
01292                                         log_debug_info(DEBUGL_EVENTS|DEBUGL_CHECKS,1,"Skip event, removing host '%s' from list.\n", temp_host->name);
01293                                         temp_event=event_list_low;
01294                                         remove_event(temp_event,&event_list_low,&event_list_low_tail);
01295                                         /*
01296                                         event_list_low=event_list_low->next;
01297                                         */
01298                                         if(temp_host->state_type==SOFT_STATE && temp_host->current_state!=STATE_OK)
01299                                                 temp_host->next_check=(time_t)(temp_host->next_check+(temp_host->retry_interval*interval_length));
01300                                         else
01301                                                 temp_host->next_check=(time_t)(temp_host->next_check+(temp_host->check_interval*interval_length));
01302 
01303                                         temp_event->run_time=temp_host->next_check;
01304                                         reschedule_event(temp_event,&event_list_low,&event_list_low_tail);
01305                                         update_host_status(temp_host,FALSE);
01306 
01307                                         run_event=FALSE;
01308                                         }
01309                                 }
01310 
01311                         /* run the event */
01312                         if(run_event==TRUE){
01313 
01314                                 /* remove the first event from the timing loop */
01315                                 temp_event=event_list_low;
01316                                 event_list_low=event_list_low->next;
01317                                 /* we may have just removed the only item from the list */
01318                                 if(event_list_low!=NULL)
01319                                         event_list_low->prev=NULL;
01320 
01321                                 log_debug_info(DEBUGL_EVENTS,1,"Running event...\n");
01322 
01323 #                               /* handle the event */
01324                                 handle_timed_event(temp_event);
01325 
01326                                 /* reschedule the event if necessary */
01327                                 if(temp_event->recurring==TRUE)
01328                                         reschedule_event(temp_event,&event_list_low,&event_list_low_tail);
01329 
01330                                 /* else free memory associated with the event */
01331                                 else
01332                                         my_free(temp_event);
01333                                 }
01334 
01335                         }
01336 
01337                 /* we don't have anything to do at this moment in time... */
01338                 else if((event_list_high==NULL || (current_time<event_list_high->run_time)) && (event_list_low==NULL || (current_time<event_list_low->run_time))){
01339 
01340                         log_debug_info(DEBUGL_EVENTS,2,"No events to execute at the moment.  Idling for a bit...\n");
01341 
01342                         /* check for external commands if we're supposed to check as often as possible */
01343                         if(command_check_interval==-1)
01344                                 check_for_external_commands();
01345 
01346                         /* set time to sleep so we don't hog the CPU... */
01347 #ifdef USE_NANOSLEEP
01348                         delay.tv_sec=(time_t)sleep_time;
01349                         delay.tv_nsec=(long)((sleep_time-(double)delay.tv_sec)*1000000000);
01350 #else
01351                         delay.tv_sec=(time_t)sleep_time;
01352                         if(delay.tv_sec==0L)
01353                                 delay.tv_sec=1;
01354                         delay.tv_nsec=0L;
01355 #endif
01356 
01357 #ifdef USE_EVENT_BROKER
01358                         /* populate fake "sleep" event */
01359                         sleep_event.run_time=current_time;
01360                         sleep_event.event_data=(void *)&delay;
01361 
01362                         /* send event data to broker */
01363                         broker_timed_event(NEBTYPE_TIMEDEVENT_SLEEP,NEBFLAG_NONE,NEBATTR_NONE,&sleep_event,NULL);
01364 #endif
01365 
01366                         /* wait a while so we don't hog the CPU... */
01367 #ifdef USE_NANOSLEEP
01368                         nanosleep(&delay,NULL);
01369 #else
01370                         sleep((unsigned int)delay.tv_sec);
01371 #endif
01372                         }
01373 
01374                 /* update status information occassionally - NagVis watches the NDOUtils DB to see if Icinga is alive */
01375                 if((unsigned long)(current_time-last_status_update)>5){
01376                         last_status_update=current_time;
01377                         update_program_status(FALSE);
01378                         }
01379 
01380 /* make sure gcc3 won't hit here */
01381 #ifndef GCCTOOOLD
01382                 if(event_profiling_enabled)
01383                         profiler_update(EVENT_LOOP_COMPLETION, start);
01384 #endif
01385 
01386                 }
01387 
01388         log_debug_info(DEBUGL_FUNCTIONS,0,"event_execution_loop() end\n");
01389 
01390         return OK;
01391         }
01392 
01393 
01394 
01395 /* handles a timed event */
01396 int handle_timed_event(timed_event *event){
01397         host *temp_host=NULL;
01398         service *temp_service=NULL;
01399         void (*userfunc)(void *);
01400         struct timeval tv;
01401         double latency=0.0;
01402 /* make sure gcc3 won't hit here */
01403 #ifndef GCCTOOOLD
01404         struct timeval start;
01405         gettimeofday(&start,NULL);
01406 #endif
01407 
01408         log_debug_info(DEBUGL_FUNCTIONS,0,"handle_timed_event() start\n");
01409 
01410 #ifdef USE_EVENT_BROKER
01411         /* send event data to broker */
01412         broker_timed_event(NEBTYPE_TIMEDEVENT_EXECUTE,NEBFLAG_NONE,NEBATTR_NONE,event,NULL);
01413 #endif
01414 
01415         log_debug_info(DEBUGL_EVENTS,0,"** Timed Event ** Type: %d, Run Time: %s",event->event_type,ctime(&event->run_time));
01416 
01417         /* how should we handle the event? */
01418         switch(event->event_type){
01419 
01420         case EVENT_SERVICE_CHECK:
01421 
01422                 temp_service=(service *)event->event_data;
01423 
01424                 /* get check latency */
01425                 gettimeofday(&tv,NULL);
01426                 latency=(double)((double)(tv.tv_sec-event->run_time)+(double)(tv.tv_usec/1000)/1000.0);
01427 
01428                 log_debug_info(DEBUGL_EVENTS,0,"** Service Check Event ==> Host: '%s', Service: '%s', Options: %d, Latency: %f sec\n",temp_service->host_name,temp_service->description,event->event_options,latency);
01429 
01430                 /* run the service check */
01431                 temp_service=(service *)event->event_data;
01432                 run_scheduled_service_check(temp_service,event->event_options,latency);
01433                 break;
01434 
01435         case EVENT_HOST_CHECK:
01436 
01437                 temp_host=(host *)event->event_data;
01438 
01439                 /* get check latency */
01440                 gettimeofday(&tv,NULL);
01441                 latency=(double)((double)(tv.tv_sec-event->run_time)+(double)(tv.tv_usec/1000)/1000.0);
01442 
01443                 log_debug_info(DEBUGL_EVENTS,0,"** Host Check Event ==> Host: '%s', Options: %d, Latency: %f sec\n",temp_host->name,event->event_options,latency);
01444 
01445                 /* run the host check */
01446                 temp_host=(host *)event->event_data;
01447                 perform_scheduled_host_check(temp_host,event->event_options,latency);
01448                 break;
01449 
01450         case EVENT_COMMAND_CHECK:
01451 
01452                 log_debug_info(DEBUGL_EVENTS,0,"** External Command Check Event\n");
01453 
01454                 /* check for external commands */
01455                 check_for_external_commands();
01456                 break;
01457 
01458         case EVENT_LOG_ROTATION:
01459 
01460                 log_debug_info(DEBUGL_EVENTS,0,"** Log File Rotation Event\n");
01461 
01462                 /* rotate the log file */
01463                 rotate_log_file(event->run_time);
01464                 break;
01465 
01466         case EVENT_PROGRAM_SHUTDOWN:
01467 
01468                 log_debug_info(DEBUGL_EVENTS,0,"** Program Shutdown Event\n");
01469 
01470                 /* set the shutdown flag */
01471                 sigshutdown=TRUE;
01472 
01473                 /* log the shutdown */
01474                 logit(NSLOG_PROCESS_INFO,TRUE,"PROGRAM_SHUTDOWN event encountered, shutting down...\n");
01475                 break;
01476 
01477         case EVENT_PROGRAM_RESTART:
01478 
01479                 log_debug_info(DEBUGL_EVENTS,0,"** Program Restart Event\n");
01480 
01481                 /* set the restart flag */
01482                 sigrestart=TRUE;
01483 
01484                 /* log the restart */
01485                 logit(NSLOG_PROCESS_INFO,TRUE,"PROGRAM_RESTART event encountered, restarting...\n");
01486                 break;
01487 
01488         case EVENT_CHECK_REAPER:
01489 
01490                 log_debug_info(DEBUGL_EVENTS,0,"** Check Result Reaper\n");
01491 
01492                 /* reap host and service check results */
01493                 reap_check_results();
01494                 break;
01495 
01496         case EVENT_ORPHAN_CHECK:
01497 
01498                 log_debug_info(DEBUGL_EVENTS,0,"** Orphaned Host and Service Check Event\n");
01499 
01500                 /* check for orphaned hosts and services */
01501                 if(check_orphaned_hosts==TRUE)
01502                         check_for_orphaned_hosts();
01503                 if(check_orphaned_services==TRUE)
01504                         check_for_orphaned_services();
01505                 break;
01506 
01507         case EVENT_RETENTION_SAVE:
01508 
01509                 log_debug_info(DEBUGL_EVENTS,0,"** Retention Data Save Event\n");
01510 
01511                 /* save state retention data */
01512                 save_state_information(TRUE);
01513                 break;
01514 
01515         case EVENT_STATUS_SAVE:
01516 
01517                 log_debug_info(DEBUGL_EVENTS,0,"** Status Data Save Event\n");
01518 
01519                 /* save all status data (program, host, and service) */
01520                 update_all_status_data();
01521                 break;
01522 
01523         case EVENT_SCHEDULED_DOWNTIME:
01524 
01525                 log_debug_info(DEBUGL_EVENTS,0,"** Scheduled Downtime Event\n");
01526 
01527                 /* process scheduled downtime info */
01528                 if(event->event_data){
01529                         handle_scheduled_downtime_by_id(*(unsigned long *)event->event_data);
01530                         free(event->event_data);
01531                         event->event_data=NULL;
01532                         }
01533                 break;
01534 
01535         case EVENT_SFRESHNESS_CHECK:
01536 
01537                 log_debug_info(DEBUGL_EVENTS,0,"** Service Result Freshness Check Event\n");
01538 
01539                 /* check service result freshness */
01540                 check_service_result_freshness();
01541                 break;
01542 
01543         case EVENT_HFRESHNESS_CHECK:
01544 
01545                 log_debug_info(DEBUGL_EVENTS,0,"** Host Result Freshness Check Event\n");
01546 
01547                 /* check host result freshness */
01548                 check_host_result_freshness();
01549                 break;
01550 
01551         case EVENT_EXPIRE_DOWNTIME:
01552 
01553                 log_debug_info(DEBUGL_EVENTS,0,"** Expire Downtime Event\n");
01554 
01555                 /* check for expired scheduled downtime entries */
01556                 check_for_expired_downtime();
01557                 break;
01558 
01559         case EVENT_RESCHEDULE_CHECKS:
01560 
01561                 /* adjust scheduling of host and service checks */
01562                 log_debug_info(DEBUGL_EVENTS,0,"** Reschedule Checks Event\n");
01563 
01564                 adjust_check_scheduling();
01565                 break;
01566 
01567         case EVENT_EXPIRE_COMMENT:
01568 
01569                 log_debug_info(DEBUGL_EVENTS,0,"** Expire Comment Event\n");
01570 
01571                 /* check for expired comment */
01572                 check_for_expired_comment((unsigned long)event->event_data);
01573                 break;
01574 
01575         case EVENT_USER_FUNCTION:
01576 
01577                 log_debug_info(DEBUGL_EVENTS,0,"** User Function Event\n");
01578 
01579                 /* run a user-defined function */
01580                 if(event->event_data!=NULL){
01581                         userfunc=event->event_data;
01582                         (*userfunc)(event->event_args);
01583                         }
01584                 break;
01585 
01586         default:
01587 
01588                 break;
01589                 }
01590 
01591         log_debug_info(DEBUGL_FUNCTIONS,0,"handle_timed_event() end\n");
01592 
01593 /* make sure gcc3 won't hit here */
01594 #ifndef GCCTOOOLD
01595         if(event_profiling_enabled)
01596                 profiler_update(event->event_type,start);
01597 #endif
01598 
01599         return OK;
01600         }
01601 
01602 
01603 
01604 /* adjusts scheduling of host and service checks */
01605 void adjust_check_scheduling(void){
01606         timed_event *temp_event=NULL;
01607         service *temp_service=NULL;
01608         host *temp_host=NULL;
01609         double projected_host_check_overhead=0.1;
01610         double projected_service_check_overhead=0.1;
01611         time_t current_time=0L;
01612         time_t first_window_time=0L;
01613         time_t last_window_time=0L;
01614         time_t last_check_time=0L;
01615         time_t new_run_time=0L;
01616         int total_checks=0;
01617         int current_check=0;
01618         double inter_check_delay=0.0;
01619         double current_icd_offset=0.0;
01620         double total_check_exec_time=0.0;
01621         double last_check_exec_time=0.0;
01622         int adjust_scheduling=FALSE;
01623         double exec_time_factor=0.0;
01624         double current_exec_time=0.0;
01625         double current_exec_time_offset=0.0;
01626         double new_run_time_offset=0.0;
01627 
01628 
01629         log_debug_info(DEBUGL_FUNCTIONS,0,"adjust_check_scheduling() start\n");
01630 
01631         /* TODO:
01632            - Track host check overhead on a per-host basis
01633            - Figure out how to calculate service check overhead 
01634         */
01635 
01636         /* determine our adjustment window */
01637         time(&current_time);
01638         first_window_time=current_time;
01639         last_window_time=first_window_time+auto_rescheduling_window;
01640 
01641         /* get current scheduling data */
01642         for(temp_event=event_list_low;temp_event!=NULL;temp_event=temp_event->next){
01643 
01644                 /* skip events outside of our current window */
01645                 if(temp_event->run_time<=first_window_time)
01646                         continue;
01647                 if(temp_event->run_time>last_window_time)
01648                         break;
01649 
01650                 if(temp_event->event_type==EVENT_HOST_CHECK){
01651 
01652                         if((temp_host=(host *)temp_event->event_data)==NULL)
01653                                 continue;
01654 
01655                         /* ignore forced checks */
01656                         if(temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION)
01657                                 continue;
01658 
01659                         /* does the last check "bump" into this one? */
01660                         if((unsigned long)(last_check_time+last_check_exec_time)>temp_event->run_time)
01661                                 adjust_scheduling=TRUE;
01662         
01663                         last_check_time=temp_event->run_time;
01664 
01665                         /* calculate time needed to perform check */
01666                         /* NOTE: host check execution time is not taken into account, as scheduled host checks are run in parallel */
01667                         last_check_exec_time=projected_host_check_overhead;
01668                         total_check_exec_time+=last_check_exec_time;
01669                         }
01670 
01671                 else if(temp_event->event_type==EVENT_SERVICE_CHECK){
01672 
01673                         if((temp_service=(service *)temp_event->event_data)==NULL)
01674                                 continue;
01675 
01676                         /* ignore forced checks */
01677                         if(temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION)
01678                                 continue;
01679 
01680                         /* does the last check "bump" into this one? */
01681                         if((unsigned long)(last_check_time+last_check_exec_time)>temp_event->run_time)
01682                                 adjust_scheduling=TRUE;
01683         
01684                         last_check_time=temp_event->run_time;
01685 
01686                         /* calculate time needed to perform check */
01687                         /* NOTE: service check execution time is not taken into account, as service checks are run in parallel */
01688                         last_check_exec_time=projected_service_check_overhead;
01689                         total_check_exec_time+=last_check_exec_time;
01690                         }
01691 
01692                 else
01693                         continue;
01694 
01695                 total_checks++;
01696                 }
01697 
01698 
01699         /* nothing to do... */
01700         if(total_checks==0 || adjust_scheduling==FALSE){
01701 
01702                 /*
01703                 printf("\n\n");
01704                 printf("NOTHING TO DO!\n");
01705                 printf("# CHECKS:    %d\n",total_checks);
01706                 printf("WINDOW TIME: %d\n",auto_rescheduling_window);
01707                 printf("EXEC TIME:   %.3f\n",total_check_exec_time);
01708                 */
01709 
01710                 return;
01711                 }
01712 
01713         if((unsigned long)total_check_exec_time>auto_rescheduling_window){
01714                 inter_check_delay=0.0;
01715                 exec_time_factor=(double)((double)auto_rescheduling_window/total_check_exec_time);
01716                 }
01717         else{
01718                 inter_check_delay=(double)((((double)auto_rescheduling_window)-total_check_exec_time)/(double)(total_checks*1.0));
01719                 exec_time_factor=1.0;
01720                 }
01721 
01722         /*
01723         printf("\n\n");
01724         printf("TOTAL CHECKS: %d\n",total_checks);
01725         printf("WINDOW TIME:  %d\n",auto_rescheduling_window);
01726         printf("EXEC TIME:    %.3f\n",total_check_exec_time);
01727         printf("ICD:          %.3f\n",inter_check_delay);
01728         printf("EXEC FACTOR:  %.3f\n",exec_time_factor);
01729         */
01730 
01731         /* adjust check scheduling */
01732         current_icd_offset=(inter_check_delay/2.0);
01733         for(temp_event=event_list_low;temp_event!=NULL;temp_event=temp_event->next){
01734 
01735                 /* skip events outside of our current window */
01736                 if(temp_event->run_time<=first_window_time)
01737                         continue;
01738                 if(temp_event->run_time>last_window_time)
01739                         break;
01740 
01741                 if(temp_event->event_type==EVENT_HOST_CHECK){
01742 
01743                         if((temp_host=(host *)temp_event->event_data)==NULL)
01744                                 continue;
01745 
01746                         /* ignore forced checks */
01747                         if(temp_host->check_options & CHECK_OPTION_FORCE_EXECUTION)
01748                                 continue;
01749 
01750                         current_exec_time=((temp_host->execution_time+projected_host_check_overhead)*exec_time_factor);
01751                         }
01752 
01753                 else if(temp_event->event_type==EVENT_SERVICE_CHECK){
01754 
01755                         if((temp_service=(service *)temp_event->event_data)==NULL)
01756                                 continue;
01757 
01758                         /* ignore forced checks */
01759                         if(temp_service->check_options & CHECK_OPTION_FORCE_EXECUTION)
01760                                 continue;
01761 
01762                         /* NOTE: service check execution time is not taken into account, as service checks are run in parallel */
01763                         current_exec_time=(projected_service_check_overhead*exec_time_factor);
01764                         }
01765 
01766                 else
01767                         continue;
01768 
01769                 current_check++;
01770                 new_run_time_offset=current_exec_time_offset+current_icd_offset;
01771                 new_run_time=(time_t)(first_window_time+(unsigned long)new_run_time_offset);
01772 
01773                 /*
01774                 printf("  CURRENT CHECK #:      %d\n",current_check);
01775                 printf("  CURRENT ICD OFFSET:   %.3f\n",current_icd_offset);
01776                 printf("  CURRENT EXEC TIME:    %.3f\n",current_exec_time);
01777                 printf("  CURRENT EXEC OFFSET:  %.3f\n",current_exec_time_offset);
01778                 printf("  NEW RUN TIME:         %lu\n",new_run_time);
01779                 */
01780 
01781                 if(temp_event->event_type==EVENT_HOST_CHECK){
01782                         temp_event->run_time=new_run_time;
01783                         temp_host->next_check=new_run_time;
01784                         update_host_status(temp_host,FALSE);
01785                         }
01786                 else{
01787                         temp_event->run_time=new_run_time;
01788                         temp_service->next_check=new_run_time;
01789                         update_service_status(temp_service,FALSE);
01790                         }
01791 
01792                 current_icd_offset+=inter_check_delay;
01793                 current_exec_time_offset+=current_exec_time;
01794                 }
01795 
01796         /* resort event list (some events may be out of order at this point) */
01797         resort_event_list(&event_list_low,&event_list_low_tail);
01798 
01799         log_debug_info(DEBUGL_FUNCTIONS,0,"adjust_check_scheduling() end\n");
01800 
01801         return;
01802         }
01803 
01804 
01805 
01806 /* attempts to compensate for a change in the system time */
01807 void compensate_for_system_time_change(unsigned long last_time, unsigned long current_time){
01808         unsigned long time_difference=0L;
01809         timed_event *temp_event=NULL;
01810         service *temp_service=NULL;
01811         host *temp_host=NULL;
01812         int days=0;
01813         int hours=0;
01814         int minutes=0;
01815         int seconds=0;
01816         time_t (*timingfunc)(void);
01817 
01818 
01819         log_debug_info(DEBUGL_FUNCTIONS,0,"compensate_for_system_time_change() start\n");
01820 
01821         /* we moved back in time... */
01822         if(last_time>current_time){
01823                 time_difference=last_time-current_time;
01824                 get_time_breakdown(time_difference,&days,&hours,&minutes,&seconds);
01825                 log_debug_info(DEBUGL_EVENTS,0,"Detected a backwards time change of %dd %dh %dm %ds.\n",days,hours,minutes,seconds);
01826                 }
01827 
01828         /* we moved into the future... */
01829         else{
01830                 time_difference=current_time-last_time;
01831                 get_time_breakdown(time_difference,&days,&hours,&minutes,&seconds);
01832                 log_debug_info(DEBUGL_EVENTS,0,"Detected a forwards time change of %dd %dh %dm %ds.\n",days,hours,minutes,seconds);
01833                 }
01834 
01835         /* log the time change */
01836         logit(NSLOG_PROCESS_INFO | NSLOG_RUNTIME_WARNING,TRUE,"Warning: A system time change of %dd %dh %dm %ds (%s in time) has been detected.  Compensating...\n",days,hours,minutes,seconds,(last_time>current_time)?"backwards":"forwards");
01837 
01838         /* adjust the next run time for all high priority timed events */
01839         for(temp_event=event_list_high;temp_event!=NULL;temp_event=temp_event->next){
01840 
01841                 /* skip special events that occur at specific times... */
01842                 if(temp_event->compensate_for_time_change==FALSE)
01843                         continue;
01844 
01845                 /* use custom timing function */
01846                 if(temp_event->timing_func!=NULL){
01847                         timingfunc=temp_event->timing_func;
01848                         temp_event->run_time=(*timingfunc)();
01849                         }
01850 
01851                 /* else use standard adjustment */
01852                 else
01853                         adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_event->run_time);
01854                 }
01855 
01856         /* resort event list (some events may be out of order at this point) */
01857         resort_event_list(&event_list_high,&event_list_high_tail);
01858 
01859         /* adjust the next run time for all low priority timed events */
01860         for(temp_event=event_list_low;temp_event!=NULL;temp_event=temp_event->next){
01861 
01862                 /* skip special events that occur at specific times... */
01863                 if(temp_event->compensate_for_time_change==FALSE)
01864                         continue;
01865 
01866                 /* use custom timing function */
01867                 if(temp_event->timing_func!=NULL){
01868                         timingfunc=temp_event->timing_func;
01869                         temp_event->run_time=(*timingfunc)();
01870                         }
01871 
01872                 /* else use standard adjustment */
01873                 else
01874                         adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_event->run_time);
01875                 }
01876 
01877         /* resort event list (some events may be out of order at this point) */
01878         resort_event_list(&event_list_low,&event_list_low_tail);
01879 
01880         /* adjust service timestamps */
01881         for(temp_service=service_list;temp_service!=NULL;temp_service=temp_service->next){
01882 
01883                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_notification);
01884                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_check);
01885                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->next_check);
01886                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_state_change);
01887                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_service->last_hard_state_change);
01888 
01889                 /* recalculate next re-notification time */
01890                 temp_service->next_notification=get_next_service_notification_time(temp_service,temp_service->last_notification);
01891 
01892                 /* update the status data */
01893                 update_service_status(temp_service,FALSE);
01894                 }
01895 
01896         /* adjust host timestamps */
01897         for(temp_host=host_list;temp_host!=NULL;temp_host=temp_host->next){
01898 
01899                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_host_notification);
01900                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_check);
01901                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->next_check);
01902                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_state_change);
01903                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_hard_state_change);
01904                 adjust_timestamp_for_time_change(last_time,current_time,time_difference,&temp_host->last_state_history_update);
01905 
01906                 /* recalculate next re-notification time */
01907                 temp_host->next_host_notification=get_next_host_notification_time(temp_host,temp_host->last_host_notification);
01908 
01909                 /* update the status data */
01910                 update_host_status(temp_host,FALSE);
01911                 }
01912 
01913         /* adjust program timestamps */
01914         adjust_timestamp_for_time_change(last_time,current_time,time_difference,&program_start);
01915         adjust_timestamp_for_time_change(last_time,current_time,time_difference,&event_start);
01916         adjust_timestamp_for_time_change(last_time,current_time,time_difference,&last_command_check);
01917 
01918         /* update the status data */
01919         update_program_status(FALSE);
01920 
01921         return;
01922         }
01923 
01924 
01925 
01926 /* resorts an event list by event execution time - needed when compensating for system time changes */
01927 void resort_event_list(timed_event **event_list, timed_event **event_list_tail){
01928         timed_event *temp_event_list=NULL;
01929         timed_event *temp_event=NULL;
01930         timed_event *next_event=NULL;
01931 
01932         log_debug_info(DEBUGL_FUNCTIONS,0,"resort_event_list()\n");
01933 
01934         /* move current event list to temp list */
01935         temp_event_list=*event_list;
01936         *event_list=NULL;
01937 
01938         /* move all events to the new event list */
01939         for(temp_event=temp_event_list;temp_event!=NULL;temp_event=next_event){
01940                 next_event=temp_event->next;
01941 
01942                 /* add the event to the newly created event list so it will be resorted */
01943                 temp_event->next=NULL;
01944                 temp_event->prev=NULL;
01945                 add_event(temp_event,event_list,event_list_tail);
01946                 }
01947 
01948         return;
01949         }
01950 
01951 
01952 
01953 /* adjusts a timestamp variable in accordance with a system time change */
01954 void adjust_timestamp_for_time_change(time_t last_time, time_t current_time, unsigned long time_difference, time_t *ts){
01955 
01956         log_debug_info(DEBUGL_FUNCTIONS,0,"adjust_timestamp_for_time_change()\n");
01957 
01958         /* we shouldn't do anything with epoch values */
01959         if(*ts==(time_t)0)
01960                 return;
01961 
01962         /* we moved back in time... */
01963         if(last_time>current_time){
01964 
01965                 /* we can't precede the UNIX epoch */
01966                 if(time_difference>(unsigned long)*ts)
01967                         *ts=(time_t)0;
01968                 else
01969                         *ts=(time_t)(*ts-time_difference);
01970                 }
01971 
01972         /* we moved into the future... */
01973         else
01974                 *ts=(time_t)(*ts+time_difference);
01975 
01976         return;
01977         }
 All Data Structures Files Functions Variables Typedefs Defines