From 7d65963c7d6176dc6bd3e642f852713b3a1aa4fe Mon Sep 17 00:00:00 2001
From: Stephen Gran <steve@lobefin.net>
Date: Tue, 21 Sep 2010 00:09:48 +0100
Subject: [PATCH] Don't skip host checks when service checks are disabled

The problem here is when a host check is scheduled after a service check,
but service checks are for disabled.  Take the following sequence:

sc1 -> hc1

when entering event_execution_loop(), run_event starts set to TRUE.
Match of a service check event is true, and servicechecks are disabled,
so run_event changes to FALSE, and the event gets re-eschuled, and
removed from the current event queue.

Next in the work queue is the hc1 event, and it is checked because the
next block is an "if" and not "else if", which would result in that event
being handled in the next loop.  In this case, as hc1 is already visible
to the queue checker, and the condition for a hostcheck event matches, and
run_event is set to FALSE from before, the hc1 event is silently skipped.

The attached test case only attempts to match this case - a host check
immediately following a service check in the work queue when service
checks are disabled.

Signed-off-by: Stephen Gran <steve@lobefin.net>
---
 base/events.c       |    3 +-
 t-tap/test_events.c |   86 ++++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 83 insertions(+), 6 deletions(-)

diff --git a/base/events.c b/base/events.c
index 0c9a91b..a0fbfc4 100644
--- a/base/events.c
+++ b/base/events.c
@@ -1082,7 +1082,6 @@ int event_execution_loop(void){
 					run_event=FALSE;
 				        }
 
-			        }
 
 			/* Removed. Reports that if you disable all service checks, service checks continue to be run. Also
 			   t-tap/test_events will fail if this flag is set - TV
@@ -1091,7 +1090,7 @@ int event_execution_loop(void){
 			/* run_event=TRUE; */
 
 			/* run a few checks before executing a host check... */
-			if(event_list_low->event_type==EVENT_HOST_CHECK){
+			}else if(event_list_low->event_type==EVENT_HOST_CHECK){
 
 				temp_host=(host *)event_list_low->event_data;
 
diff --git a/t-tap/test_events.c b/t-tap/test_events.c
index 76a1598..6a5fe94 100644
--- a/t-tap/test_events.c
+++ b/t-tap/test_events.c
@@ -92,7 +92,11 @@ service  *service_list;
 
 int check_for_expired_comment(unsigned long temp_long) {}
 void broker_timed_event(int int1, int int2, int int3, timed_event *timed_event1, struct timeval *timeval1) {}
-int perform_scheduled_host_check(host *temp_host,int int1,double double1) {}
+int perform_scheduled_host_check(host *temp_host,int int1,double double1) {
+	time_t now=0L;
+	time(&now);
+	temp_host->last_check = now;
+}
 int check_for_expired_downtime(void) {}
 int reap_check_results(void) {}
 void check_host_result_freshness() {}
@@ -108,6 +112,9 @@ time_t get_next_log_rotation_time(void) {}
 void check_for_orphaned_services() {}
 int run_scheduled_service_check(service *service1, int int1, double double1) {
 	currently_running_service_checks++;
+	time_t now=0L;
+	time(&now);
+	service1->last_check = now;
 	/* printf("Currently running service checks: %d\n", currently_running_service_checks); */
 }
 int handle_scheduled_downtime_by_id(unsigned long long1) {}
@@ -138,7 +145,8 @@ int log_debug_info(int level, int verbosity, const char *fmt, ...){
 int update_host_status(host *hst,int aggregated_dump){}
 
 /* Test variables */
-service *svc1=NULL, *svc2=NULL;
+service *svc1=NULL, *svc2=NULL, *svc3=NULL;
+host *host1=NULL;
 
 void
 setup_events(time_t time) {
@@ -191,12 +199,65 @@ setup_events(time_t time) {
 	reschedule_event(new_event,&event_list_low,&event_list_low_tail);
 }
 
+void
+setup_events_with_host(time_t time) {
+	timed_event *new_event=NULL;
+
+	/* First service is a normal one */
+	if(svc3==NULL)
+		svc3=(service *)malloc(sizeof(service));
+	svc3->host_name=strdup("Host0");
+	svc3->description=strdup("Normal service");
+	svc3->check_options=0;
+	svc3->next_check=time;
+	svc3->state_type=SOFT_STATE;
+	svc3->current_state=STATE_OK;
+	svc3->retry_interval=1;
+	svc3->check_interval=5;
+
+	new_event=(timed_event *)malloc(sizeof(timed_event));
+	new_event->event_type=EVENT_SERVICE_CHECK;
+	new_event->event_data=(void *)svc3;
+	new_event->event_args=(void *)NULL;
+	new_event->event_options=0;
+	new_event->run_time=0L;				/* Straight away */
+	new_event->recurring=FALSE;
+	new_event->event_interval=0L;
+	new_event->timing_func=NULL;
+	new_event->compensate_for_time_change=TRUE;
+	reschedule_event(new_event,&event_list_low,&event_list_low_tail);
+
+	if (host1==NULL)
+		host1=(host *)malloc(sizeof(host));
+	host1->name=strdup("Host1");
+	host1->address=strdup("127.0.0.1");
+	host1->retry_interval=1;
+	host1->check_interval=5;
+	host1->check_options=0;
+	host1->next_check=time;
+	new_event->recurring=TRUE;
+	host1->state_type=SOFT_STATE;
+	host1->current_state=STATE_OK;
+
+	new_event=(timed_event *)malloc(sizeof(timed_event));
+	new_event->event_type=EVENT_HOST_CHECK;
+	new_event->event_data=(void *)host1;
+	new_event->event_args=(void *)NULL;
+	new_event->event_options=0;
+	new_event->run_time=0L;				/* Straight away */
+	new_event->recurring=TRUE;
+	new_event->event_interval=0L;
+	new_event->timing_func=NULL;
+	new_event->compensate_for_time_change=TRUE;
+	reschedule_event(new_event,&event_list_low,&event_list_low_tail);
+}
+
 int
 main (int argc, char **argv)
 {
 	time_t now=0L;
 
-	plan_tests(6);
+	plan_tests(10);
 
 	time(&now);
 
@@ -225,13 +286,30 @@ main (int argc, char **argv)
 	execute_service_checks=0;
 	sigshutdown=FALSE;
 	currently_running_service_checks=0;
-	max_parallel_service_checks=1;
+	max_parallel_service_checks=2;
 	setup_events(now);
 	svc2->current_state=STATE_CRITICAL;
 	event_execution_loop();
 	ok(svc1->next_check == now+300, "svc1 rescheduled ahead - normal interval" );
 	ok(svc2->next_check == now+60,  "svc2 rescheduled ahead - retry interval" );
 
+	timed_event *temp_event=NULL;
+	while ((temp_event = event_list_low) != NULL) {
+		remove_event(temp_event,&event_list_low,&event_list_low_tail);
+	}
+
+	sigshutdown=FALSE;
+	currently_running_service_checks=0;
+	max_parallel_service_checks=2;
+	execute_service_checks=0;
+	execute_host_checks=1;
+	setup_events_with_host(now);
+	event_execution_loop();
+
+	ok(host1->last_check == now,  "host1 was checked" );
+	ok(svc3->last_check == 0, "svc3 was skipped" );
+	ok(host1->next_check == now,  "host1 rescheduled ahead - normal interval" );
+	ok(svc3->next_check == now+300, "svc3 rescheduled ahead - normal interval" );
 
 	return exit_status ();
 }
-- 
1.7.1

