--- jk_ajp13_worker.c.orig	Fri Mar  9 09:45:45 2001
+++ jk_ajp13_worker.c	Fri Mar  9 11:31:48 2001
@@ -54,10 +54,11 @@
  */
 
 /***************************************************************************
- * Description: Bi-directional protocol.                       *
+ * Description: Bi-directional protocol.                                   *
+ * Author:      Gomez Henri <hgomez@slib.fr>                               *
  * Author:      Costin <costin@costin.dnt.ro>                              *
  * Author:      Gal Shachor <shachor@il.ibm.com>                           *
- * Version:     $Revision: 1.5 $                                           *
+ * Version:     $Revision: 1.6 $                                           *
  ***************************************************************************/
 
 #include "jk_pool.h"
@@ -530,41 +531,31 @@
     return JK_FALSE;
 }
 
-static int JK_METHOD service(jk_endpoint_t *e, 
-                             jk_ws_service_t *s,
-                             jk_logger_t *l,
-                             int *is_recoverable_error)
+/*
+ * send request to Tomcat via Ajp13
+ * - first try to find reuseable socket
+ * - if no one available, try to connect
+ * - send request, but send must be see as asynchronous,
+ *   since send() call will return noerror about 95% of time
+ *   Hopefully we'll get more information on next read.
+ */
+static int sendrequest(jk_endpoint_t *e,
+						jk_ws_service_t *s,
+						jk_logger_t *l,
+						int *is_recoverable_error,
+						ajp13_endpoint_t *p,
+						jk_msg_buf_t *msg)
 {
-    jk_log(l, 
-           JK_LOG_DEBUG, 
-           "Into jk_endpoint_t::service\n");
-
-    if(e && e->endpoint_private && s && is_recoverable_error) {
-        ajp13_endpoint_t *p = e->endpoint_private;
-        jk_msg_buf_t *msg = jk_b_new(&(p->pool));
-
-        jk_b_set_buffer_size( msg, DEF_BUFFER_SZ); 
-	    jk_b_reset(msg);
-        
-        p->left_bytes_to_send = s->content_length;
-        p->reuse = JK_FALSE;
-        *is_recoverable_error = JK_TRUE;
-
-        if(!ajp13_marshal_into_msgb(msg, s, l)) {
-            *is_recoverable_error = JK_FALSE;                
-            return JK_FALSE;
-        }
-
         /*
          * First try to reuse open connections...
          */
         while((p->sd > 0) && !connection_tcp_send_message(p, msg, l)) {
-    	    jk_log(l, JK_LOG_ERROR,
-			       "Error sending request try another pooled connection\n");
-		    jk_close_socket(p->sd);
+            jk_log(l, JK_LOG_ERROR,
+                   "Error sending request try another pooled connection\n");
+            jk_close_socket(p->sd);
             p->sd = -1;
             reuse_connection(p, l);
-        } 
+        }
 
         /*
          * If we failed to reuse a connection, try to reconnect.
@@ -575,27 +566,27 @@
                 /*
                  * After we are connected, each error that we are going to
                  * have is probably unrecoverable
-                 */            
+                 */
                 *is_recoverable_error = JK_FALSE;
                 if(!connection_tcp_send_message(p, msg, l)) {
-    	            jk_log(l, JK_LOG_ERROR,
-			               "Error sending request on a fresh connection\n");
-		            return JK_FALSE;
-                } 
+                    jk_log(l, JK_LOG_ERROR,
+                           "Error sending request on a fresh connection\n");
+                    return JK_FALSE;
+                }
             } else {
-                jk_log(l, 
+                jk_log(l,
                        JK_LOG_ERROR,
-			           "Error connecting to the Tomcat process.\n");
-		        return JK_FALSE;
+                       "Error connecting to the Tomcat process.\n");
+                return JK_FALSE;
             }
-        } 
+        }
 
-        /* 
-         * From now on an error means that we have an internal server error 
+        /*
+         * From now on an error means that we have an internal server error
          * or Tomcat crashed. In any case we cannot recover this.
          */
         *is_recoverable_error = JK_FALSE;
-        
+
 
         if(p->left_bytes_to_send > 0) {
             unsigned len = p->left_bytes_to_send;
@@ -604,47 +595,123 @@
             }
             if(!read_into_msg_buff(p, s, msg, l, len)) {
                 return JK_FALSE;
-            }                  
+            }
             s->content_read = len;
             if(!connection_tcp_send_message(p, msg, l)) {
-    	        jk_log(l, JK_LOG_ERROR,
-			           "Error sending request body\n");
-		        return JK_FALSE;
-            }   
+                jk_log(l, JK_LOG_ERROR,
+                       "Error sending request body\n");
+                return JK_FALSE;
+            }  
         }
 
-        /*
-         * Enter the message pump.
-         */
-	    while(1) {
-            int rc = 0;
-            
-		    if(!connection_tcp_get_message(p, msg, l)) {
-		        jk_log(l, JK_LOG_ERROR,
-				       "Error reading request\n");
-		        return JK_FALSE;
-		    }
+	return (JK_TRUE);
+}
 
-            rc = ajp13_process_callback(msg, p, s, l);
-            if(JK_AJP13_END_RESPONSE == rc) {
-                return JK_TRUE;
-            } else if(JK_AJP13_HAS_RESPONSE == rc) {
-		        rc = connection_tcp_send_message(p, msg, l);
-		        if(rc < 0) {
-			        jk_log(l, JK_LOG_DEBUG,
-				           "Error reading response1 %d\n", rc);
-			        return JK_FALSE;
-		        }
-            } else if(rc < 0) {
-                break; /* XXX error */
+/*
+ * get replies from Tomcat via Ajp13
+ * We will know only at read time if the remote host closed
+ * the connection (half-closed state - FIN-WAIT2). In that case
+ * we must close our side of the socket and abort emission.
+ * We will need another connection to send the request
+ */
+
+static int getreply(jk_endpoint_t *e,
+                        jk_ws_service_t *s,
+                        jk_logger_t *l,
+                        int *is_recoverable_error,
+						ajp13_endpoint_t *p,
+                        jk_msg_buf_t *msg,
+                        jk_msg_buf_t *rmsg)
+{
+	/* Start read all reply message */
+
+    while(1) {
+        int rc = 0;
+
+		if(!connection_tcp_get_message(p, rmsg, l)) {
+			jk_log(l, JK_LOG_ERROR, "Error reading request\n");
+			return JK_FALSE;
+		}
+
+		rc = ajp13_process_callback(rmsg, p, s, l);
+        if(JK_AJP13_END_RESPONSE == rc)
+        	return JK_TRUE;
+        else if(JK_AJP13_HAS_RESPONSE == rc) {
+			rc = connection_tcp_send_message(p, msg, l);
+            if (rc < 0) {
+				jk_log(l, JK_LOG_DEBUG, "Error reading response1 %d\n", rc);
+                return JK_FALSE;
             }
-	    }        
+		} else if(rc < 0) {
+			return (JK_FALSE); /* XXX error */
+		}
+	}
+}
+
+#define	JK_RETRIES 3
+
+/*
+ * service is now splitted in sendrequest and getreply
+ * much more easier to do errors recovery
+ */
+static int JK_METHOD service(jk_endpoint_t *e, 
+                             jk_ws_service_t *s,
+                             jk_logger_t *l,
+                             int *is_recoverable_error)
+{
+	jk_msg_buf_t *msg, *rmsg;
+	int i = JK_RETRIES;	/* could be replaced here by the number of workers in
+                           a load-balancing configuration */
+
+    jk_log(l, 
+           JK_LOG_DEBUG, 
+           "Into jk_endpoint_t::service\n");
+
+    if(e && e->endpoint_private && s && is_recoverable_error) {
+        ajp13_endpoint_t *p = e->endpoint_private;
+        msg = jk_b_new(&(p->pool));
+        jk_b_set_buffer_size( msg, DEF_BUFFER_SZ); 
+	    jk_b_reset(msg);
+        rmsg = jk_b_new(&(p->pool));
+        jk_b_set_buffer_size( rmsg, DEF_BUFFER_SZ); 
+	    jk_b_reset(rmsg);
+        
+        
+        p->left_bytes_to_send = s->content_length;
+        p->reuse = JK_FALSE;
+        *is_recoverable_error = JK_TRUE;
+
+        if(!ajp13_marshal_into_msgb(msg, s, l)) {
+            *is_recoverable_error = JK_FALSE;                
+            return JK_FALSE;
+        }
+	
+		for (; i; i--)
+		{
+			if (! sendrequest(e, s, l, is_recoverable_error, p, msg))
+			{
+				jk_log(l, JK_LOG_ERROR,"sendrequest failed in send loop %d\n", i);
+				continue;
+			}
+
+			*is_recoverable_error = JK_TRUE;
+
+			if (getreply(e, s, l, is_recoverable_error, p, msg, rmsg))
+				return (JK_TRUE);
+
+			jk_log(l, JK_LOG_DEBUG, "getreply failed in send loop %d\n", i);
+
+            jk_close_socket(p->sd);
+            p->sd = -1;
+            reuse_connection(p, l);
+		}
     } else {
-        jk_log(l, 
-               JK_LOG_ERROR, 
+        jk_log(l,
+               JK_LOG_ERROR,
                "In jk_endpoint_t::service, NULL parameters\n");
-    }
-
+	}
+	
+	*is_recoverable_error = JK_FALSE;
     return JK_FALSE;
 }
 

