From e2edaa6b637227c70ec6dc0f0d00de4d5fe5b620 Mon Sep 17 00:00:00 2001
From: Vincent Bernat <bernat@luffy.cx>
Date: Mon, 06 Jun 2011 07:01:54 +0000
Subject: checker: keep retry in case of early TCP failures in checks

Patch from Brad Schick. Original mail:

Two patched attached. It turns out that 1.1.20 and 1.2.2 each had some
partial implementations of my proposed improvements already, but they
are inconsistent. And I believe in the case of 1.2.2, the existing
implementation leaks socket handles.

These patches cleanup 1.1.20 and 1.2.2 respectively and make both of
them continue to retry after socket creation and bind failures. I also
added INFO level logging rather than DGB only since this is very
helpful information when things aren't working as expected.

I also fixed another random mis-use of the DBG macro that I noticed in
both 1.1.20 and 1.2.2. Patches attached.
---
diff --git a/keepalived/check/check_http.c b/keepalived/check/check_http.c
index 0d1a12c..3d2e46b 100644
--- a/keepalived/check/check_http.c
+++ b/keepalived/check/check_http.c
@@ -793,7 +793,7 @@ http_check_thread(thread_t * thread)
 						 thread->u.fd,
 						 http_get_check->connection_to);
 			} else {
-				DBG(LOG_INFO, "Connection trouble to: [%s]:%d."
+				DBG("Connection trouble to: [%s]:%d."
 					    , inet_sockaddrtos(&http_get_check->dst)
 					    , ntohs(inet_sockaddrport(&http_get_check->dst)));
 #ifdef _DEBUG_
@@ -871,19 +871,23 @@ http_connect_thread(thread_t * thread)
 
 	/* Create the socket */
 	if ((fd = socket(http_get_check->dst.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
-		DBG("WEB connection fail to create socket.");
+		log_message(LOG_INFO, "WEB connection fail to create socket. Rescheduling.");
+		thread_add_timer(thread->master, http_connect_thread, checker,
+				checker->vs->delay_loop);
+ 
 		return 0;
 	}
 
 	status = tcp_bind_connect(fd, &http_get_check->dst, &http_get_check->bindto);
-	if (status == connect_error) {
+
+	/* handle tcp connection status & register check worker thread */
+	if(tcp_connection_state(fd, status, thread, http_check_thread,
+			http_get_check->connection_to)) {
+		close(fd);
+		log_message(LOG_INFO, "WEB socket bind failed. Rescheduling");
 		thread_add_timer(thread->master, http_connect_thread, checker,
-				 checker->vs->delay_loop);
-		return 0;
+				checker->vs->delay_loop);
 	}
 
-	/* handle tcp connection status & register check worker thread */
-	tcp_connection_state(fd, status, thread, http_check_thread,
-			     http_get_check->connection_to);
 	return 0;
 }
diff --git a/keepalived/check/check_smtp.c b/keepalived/check/check_smtp.c
index 79a8f5b..bf62a8c 100644
--- a/keepalived/check/check_smtp.c
+++ b/keepalived/check/check_smtp.c
@@ -811,20 +811,21 @@ smtp_connect_thread(thread_t *thread)
 
 	/* Create the socket, failling here should be an oddity */
 	if ((sd = socket(smtp_host->dst.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
-		DBG("SMTP_CHECK connection failed to create socket.");
+		log_message(LOG_INFO, "SMTP_CHECK connection failed to create socket. Rescheduling.");
 		thread_add_timer(thread->master, smtp_connect_thread, checker,
 				 checker->vs->delay_loop);
 		return 0;
 	}
 
 	status = tcp_bind_connect(sd, &smtp_host->dst, &smtp_host->bindto);
-	if (status == connect_error) {
-		thread_add_timer(thread->master, smtp_connect_thread, checker,
-				 checker->vs->delay_loop);
-		return 0;
-	}
 
 	/* handle tcp connection status & register callback the next setp in the process */
-	tcp_connection_state(sd, status, thread, smtp_check_thread, smtp_checker->timeout);
+	if(tcp_connection_state(sd, status, thread, smtp_check_thread, smtp_checker->timeout)) {
+		close(sd);
+		log_message(LOG_INFO, "SMTP_CHECK socket bind failed. Rescheduling.");
+		thread_add_timer(thread->master, smtp_connect_thread, checker,
+			checker->vs->delay_loop);
+	}
+ 
 	return 0;
 }
diff --git a/keepalived/check/check_tcp.c b/keepalived/check/check_tcp.c
index e0fb077..9f2b3e8 100644
--- a/keepalived/check/check_tcp.c
+++ b/keepalived/check/check_tcp.c
@@ -169,19 +169,23 @@ tcp_connect_thread(thread_t * thread)
 	}
 
 	if ((fd = socket(tcp_check->dst.ss_family, SOCK_STREAM, IPPROTO_TCP)) == -1) {
-		DBG("TCP connect fail to create socket.");
+		log_message(LOG_INFO, "TCP connect fail to create socket. Rescheduling.");
+		thread_add_timer(thread->master, tcp_connect_thread, checker,
+				checker->vs->delay_loop);
+ 
 		return 0;
 	}
 
 	status = tcp_bind_connect(fd, &tcp_check->dst, &tcp_check->bindto);
-	if (status == connect_error) {
-		thread_add_timer(thread->master, tcp_connect_thread, checker,
-				 checker->vs->delay_loop);
-		return 0;
-	}
 
 	/* handle tcp connection status & register check worker thread */
-	tcp_connection_state(fd, status, thread, tcp_check_thread,
-			     tcp_check->connection_to);
+	if(tcp_connection_state(fd, status, thread, tcp_check_thread,
+			tcp_check->connection_to)) {
+		close(fd);
+		log_message(LOG_INFO, "TCP socket bind failed. Rescheduling.");
+		thread_add_timer(thread->master, tcp_connect_thread, checker,
+				checker->vs->delay_loop);
+	}
+ 
 	return 0;
 }
diff --git a/keepalived/core/layer4.c b/keepalived/core/layer4.c
index ce2035e..5725500 100644
--- a/keepalived/core/layer4.c
+++ b/keepalived/core/layer4.c
@@ -119,7 +119,7 @@ tcp_socket_state(int fd, thread_t * thread, int (*func) (thread_t *))
 	return connect_success;
 }
 
-void
+int
 tcp_connection_state(int fd, enum connect_result status, thread_t * thread,
 		     int (*func) (thread_t *), long timeout)
 {
@@ -128,20 +128,16 @@ tcp_connection_state(int fd, enum connect_result status, thread_t * thread,
 	checker = THREAD_ARG(thread);
 
 	switch (status) {
-	case connect_error:
-		close(fd);
-		break;
-
 	case connect_success:
 		thread_add_write(thread->master, func, checker, fd, timeout);
-		break;
+		return 0;
 
 		/* Checking non-blocking connect, we wait until socket is writable */
 	case connect_in_progress:
 		thread_add_write(thread->master, func, checker, fd, timeout);
-		break;
+		return 0;
 
 	default:
-		break;
+		return 1;
 	}
 }
diff --git a/keepalived/include/layer4.h b/keepalived/include/layer4.h
index 857927b..ad2fc57 100644
--- a/keepalived/include/layer4.h
+++ b/keepalived/include/layer4.h
@@ -52,7 +52,7 @@ extern enum connect_result
 extern enum connect_result
  tcp_socket_state(int, thread_t *, int (*func) (thread_t *));
 
-extern void
+extern int
  tcp_connection_state(int, enum connect_result
 		      , thread_t *, int (*func) (thread_t *)
 		      , long);
--
cgit v0.8.3.4
