bottleneck testcase based on rubbos
[bottlenecks.git] / rubbos / app / tomcat-connectors-1.2.32-src / native / common / jk_ajp_common.c
1 /*
2  *  Licensed to the Apache Software Foundation (ASF) under one or more
3  *  contributor license agreements.  See the NOTICE file distributed with
4  *  this work for additional information regarding copyright ownership.
5  *  The ASF licenses this file to You under the Apache License, Version 2.0
6  *  (the "License"); you may not use this file except in compliance with
7  *  the License.  You may obtain a copy of the License at
8  *
9  *      http://www.apache.org/licenses/LICENSE-2.0
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  */
17
18 /***************************************************************************
19  * Description: common stuff for bi-directional protocols ajp13/ajp14.     *
20  * Author:      Gal Shachor <shachor@il.ibm.com>                           *
21  * Author:      Henri Gomez <hgomez@apache.org>                            *
22  * Version:     $Revision: 1137200 $                                          *
23  ***************************************************************************/
24
25
26 #include "jk_global.h"
27 #include "jk_util.h"
28 #include "jk_ajp13.h"
29 #include "jk_ajp14.h"
30 #include "jk_ajp_common.h"
31 #include "jk_connect.h"
32 #if defined(AS400) && !defined(AS400_UTF8)
33 #include "util_ebcdic.h"
34 #endif
35 #if defined(NETWARE) && defined(__NOVELL_LIBC__)
36 #include "novsock2.h"
37 #endif
38
39 const char *response_trans_headers[] = {
40     "Content-Type",
41     "Content-Language",
42     "Content-Length",
43     "Date",
44     "Last-Modified",
45     "Location",
46     "Set-Cookie",
47     "Set-Cookie2",
48     "Servlet-Engine",
49     "Status",
50     "WWW-Authenticate"
51 };
52
53 static const char *long_res_header_for_sc(int sc)
54 {
55     const char *rc = NULL;
56     sc = sc & 0X00FF;
57     if (sc <= SC_RES_HEADERS_NUM && sc > 0) {
58         rc = response_trans_headers[sc - 1];
59     }
60
61     return rc;
62 }
63
64 static const char *ajp_state_type[] = {
65     JK_AJP_STATE_TEXT_IDLE,
66     JK_AJP_STATE_TEXT_OK,
67     JK_AJP_STATE_TEXT_ERROR,
68     JK_AJP_STATE_TEXT_PROBE,
69     "unknown",
70     NULL
71 };
72
73 #define UNKNOWN_METHOD (-1)
74
75 static int sc_for_req_method(const char *method, size_t len)
76 {
77     /* Note: the following code was generated by the "shilka" tool from
78        the "cocom" parsing/compilation toolkit. It is an optimized lookup
79        based on analysis of the input keywords. Postprocessing was done
80        on the shilka output, but the basic structure and analysis is
81        from there. Should new HTTP methods be added, then manual insertion
82        into this code is fine, or simply re-running the shilka tool on
83        the appropriate input. */
84
85     /* Note: it is also quite reasonable to just use our method_registry,
86        but I'm assuming (probably incorrectly) we want more speed here
87        (based on the optimizations the previous code was doing). */
88
89     switch (len)
90     {
91     case 3:
92         switch (method[0])
93         {
94         case 'A':
95             return (method[1] == 'C'
96                     && method[2] == 'L'
97                     ? SC_M_ACL : UNKNOWN_METHOD);
98         case 'P':
99             return (method[1] == 'U'
100                     && method[2] == 'T'
101                     ? SC_M_PUT : UNKNOWN_METHOD);
102         case 'G':
103             return (method[1] == 'E'
104                     && method[2] == 'T'
105                     ? SC_M_GET : UNKNOWN_METHOD);
106         default:
107             return UNKNOWN_METHOD;
108         }
109
110     case 4:
111         switch (method[0])
112         {
113         case 'H':
114             return (method[1] == 'E'
115                     && method[2] == 'A'
116                     && method[3] == 'D'
117                     ? SC_M_HEAD : UNKNOWN_METHOD);
118         case 'P':
119             return (method[1] == 'O'
120                     && method[2] == 'S'
121                     && method[3] == 'T'
122                     ? SC_M_POST : UNKNOWN_METHOD);
123         case 'M':
124             return (method[1] == 'O'
125                     && method[2] == 'V'
126                     && method[3] == 'E'
127                     ? SC_M_MOVE : UNKNOWN_METHOD);
128         case 'L':
129             return (method[1] == 'O'
130                     && method[2] == 'C'
131                     && method[3] == 'K'
132                     ? SC_M_LOCK : UNKNOWN_METHOD);
133         case 'C':
134             return (method[1] == 'O'
135                     && method[2] == 'P'
136                     && method[3] == 'Y'
137                     ? SC_M_COPY : UNKNOWN_METHOD);
138         default:
139             return UNKNOWN_METHOD;
140         }
141
142     case 5:
143         switch (method[2])
144         {
145         case 'R':
146             return (memcmp(method, "MERGE", 5) == 0
147                     ? SC_M_MERGE : UNKNOWN_METHOD);
148         case 'C':
149             return (memcmp(method, "MKCOL", 5) == 0
150                     ? SC_M_MKCOL : UNKNOWN_METHOD);
151         case 'B':
152             return (memcmp(method, "LABEL", 5) == 0
153                     ? SC_M_LABEL : UNKNOWN_METHOD);
154         case 'A':
155             return (memcmp(method, "TRACE", 5) == 0
156                     ? SC_M_TRACE : UNKNOWN_METHOD);
157         default:
158             return UNKNOWN_METHOD;
159         }
160
161     case 6:
162         switch (method[0])
163         {
164         case 'U':
165             switch (method[5])
166             {
167             case 'K':
168                 return (memcmp(method, "UNLOCK", 6) == 0
169                         ? SC_M_UNLOCK : UNKNOWN_METHOD);
170             case 'E':
171                 return (memcmp(method, "UPDATE", 6) == 0
172                         ? SC_M_UPDATE : UNKNOWN_METHOD);
173             default:
174                 return UNKNOWN_METHOD;
175             }
176         case 'R':
177             return (memcmp(method, "REPORT", 6) == 0
178                     ? SC_M_REPORT : UNKNOWN_METHOD);
179         case 'S':
180             return (memcmp(method, "SEARCH", 6) == 0
181                     ? SC_M_SEARCH : UNKNOWN_METHOD);
182         case 'D':
183             return (memcmp(method, "DELETE", 6) == 0
184                     ? SC_M_DELETE : UNKNOWN_METHOD);
185         default:
186             return UNKNOWN_METHOD;
187         }
188
189     case 7:
190         switch (method[1])
191         {
192         case 'P':
193             return (memcmp(method, "OPTIONS", 7) == 0
194                     ? SC_M_OPTIONS : UNKNOWN_METHOD);
195         case 'H':
196             return (memcmp(method, "CHECKIN", 7) == 0
197                     ? SC_M_CHECKIN : UNKNOWN_METHOD);
198         default:
199             return UNKNOWN_METHOD;
200         }
201
202     case 8:
203         switch (method[0])
204         {
205         case 'P':
206             return (memcmp(method, "PROPFIND", 8) == 0
207                     ? SC_M_PROPFIND : UNKNOWN_METHOD);
208         case 'C':
209             return (memcmp(method, "CHECKOUT", 8) == 0
210                     ? SC_M_CHECKOUT : UNKNOWN_METHOD);
211         default:
212             return UNKNOWN_METHOD;
213         }
214
215     case 9:
216         return (memcmp(method, "PROPPATCH", 9) == 0
217                 ? SC_M_PROPPATCH : UNKNOWN_METHOD);
218
219     case 10:
220         switch (method[0])
221         {
222         case 'U':
223             return (memcmp(method, "UNCHECKOUT", 10) == 0
224                     ? SC_M_UNCHECKOUT : UNKNOWN_METHOD);
225         case 'M':
226             return (memcmp(method, "MKACTIVITY", 10) == 0
227                     ? SC_M_MKACTIVITY : UNKNOWN_METHOD);
228         default:
229             return UNKNOWN_METHOD;
230         }
231
232     case 11:
233         return (memcmp(method, "MKWORKSPACE", 11) == 0
234                 ? SC_M_MKWORKSPACE : UNKNOWN_METHOD);
235
236     case 15:
237         return (memcmp(method, "VERSION-CONTROL", 15) == 0
238                 ? SC_M_VERSION_CONTROL : UNKNOWN_METHOD);
239
240     case 16:
241         return (memcmp(method, "BASELINE-CONTROL", 16) == 0
242                 ? SC_M_BASELINE_CONTROL : UNKNOWN_METHOD);
243
244     default:
245         return UNKNOWN_METHOD;
246     }
247
248     /* NOTREACHED */
249 }
250
251 static int sc_for_req_header(const char *header_name)
252 {
253     char header[16];
254     size_t len = strlen(header_name);
255     const char *p = header_name;
256     int i = 0;
257
258     /* ACCEPT-LANGUAGE is the longest header
259      * that is of interest.
260      */
261     if (len < 4 || len > 15)
262         return UNKNOWN_METHOD;
263
264     while (*p) {
265         header[i++] = toupper((unsigned char)*p);
266         p++;
267     }
268
269     header[i] = '\0';
270     p = &header[1];
271
272 /* Always do memcmp including the final \0-termination character.
273  */
274     switch (header[0]) {
275         case 'A':
276             if (memcmp(p, "CCEPT", 6) == 0) {
277                 if (!header[6])
278                     return SC_ACCEPT;
279                 else if (header[6] == '-') {
280                     p += 6;
281                     if (memcmp(p, "CHARSET", 8) == 0)
282                         return SC_ACCEPT_CHARSET;
283                     else if (memcmp(p,  "ENCODING", 9) == 0)
284                         return SC_ACCEPT_ENCODING;
285                     else if (memcmp(p, "LANGUAGE", 9) == 0)
286                         return SC_ACCEPT_LANGUAGE;
287                     else
288                         return UNKNOWN_METHOD;
289                 }
290                 else
291                     return UNKNOWN_METHOD;
292             }
293             else if (memcmp(p, "UTHORIZATION", 13) == 0)
294                 return SC_AUTHORIZATION;
295             else
296                 return UNKNOWN_METHOD;
297         break;
298         case 'C':
299             if(memcmp(p, "OOKIE2", 7) == 0)
300                 return SC_COOKIE2;
301             else if (memcmp(p, "OOKIE", 6) == 0)
302                 return SC_COOKIE;
303             else if(memcmp(p, "ONNECTION", 10) == 0)
304                 return SC_CONNECTION;
305             else if(memcmp(p, "ONTENT-TYPE", 12) == 0)
306                 return SC_CONTENT_TYPE;
307             else if(memcmp(p, "ONTENT-LENGTH", 14) == 0)
308                 return SC_CONTENT_LENGTH;
309             else
310                 return UNKNOWN_METHOD;
311         break;
312         case 'H':
313             if(memcmp(p, "OST", 4) == 0)
314                 return SC_HOST;
315             else
316                 return UNKNOWN_METHOD;
317         break;
318         case 'P':
319             if(memcmp(p, "RAGMA", 6) == 0)
320                 return SC_PRAGMA;
321             else
322                 return UNKNOWN_METHOD;
323         break;
324         case 'R':
325             if(memcmp(p, "EFERER", 7) == 0)
326                 return SC_REFERER;
327             else
328                 return UNKNOWN_METHOD;
329         break;
330         case 'U':
331             if(memcmp(p, "SER-AGENT", 10) == 0)
332                 return SC_USER_AGENT;
333             else
334                 return UNKNOWN_METHOD;
335         break;
336         default:
337             return UNKNOWN_METHOD;
338     }
339     /* NOTREACHED */
340 }
341
342 /* Return the string representation of the worker state */
343 const char *jk_ajp_get_state(ajp_worker_t *aw, jk_logger_t *l)
344 {
345     return ajp_state_type[aw->s->state];
346 }
347
348 /* Return the int representation of the worker state */
349 int jk_ajp_get_state_code(const char *v)
350 {
351     if (!v)
352         return JK_AJP_STATE_DEF;
353     else if  (*v == 'i' || *v == 'I' || *v == 'n' || *v == 'N' || *v == '0')
354         return JK_AJP_STATE_IDLE;
355     else if  (*v == 'o' || *v == 'O' || *v == '1')
356         return JK_AJP_STATE_OK;
357     else if  (*v == 'e' || *v == 'E' || *v == '4')
358         return JK_AJP_STATE_ERROR;
359     else if  (*v == 'p' || *v == 'P' || *v == '6')
360         return JK_AJP_STATE_PROBE;
361     else
362         return JK_AJP_STATE_DEF;
363 }
364
365 int jk_ajp_get_cping_mode(const char *m, int def)
366 {
367     int mv = def;
368     if (!m)
369         return mv;
370     while (*m != '\0') {
371         if (*m == 'C' || *m == 'c')
372             mv |= AJP_CPING_CONNECT;
373         else if (*m == 'P' || *m == 'p')
374             mv |= AJP_CPING_PREPOST;
375         else if (*m == 'I' || *m == 'i')
376             mv |= AJP_CPING_INTERVAL;
377         else if (*m == 'A' || *m == 'a') {
378             mv = AJP_CPING_CONNECT | AJP_CPING_PREPOST | AJP_CPING_INTERVAL;
379             break;
380         }
381         m++;
382     }
383     return mv;
384 }
385
386 /*
387  * Message structure
388  *
389  *
390 AJPV13_REQUEST/AJPV14_REQUEST=
391     request_prefix (1) (byte)
392     method         (byte)
393     protocol       (string)
394     req_uri        (string)
395     remote_addr    (string)
396     remote_host    (string)
397     server_name    (string)
398     server_port    (short)
399     is_ssl         (boolean)
400     num_headers    (short)
401     num_headers*(req_header_name header_value)
402
403     ?context       (byte)(string)
404     ?servlet_path  (byte)(string)
405     ?remote_user   (byte)(string)
406     ?auth_type     (byte)(string)
407     ?query_string  (byte)(string)
408     ?route         (byte)(string)
409     ?ssl_cert      (byte)(string)
410     ?ssl_cipher    (byte)(string)
411     ?ssl_session   (byte)(string)
412     ?ssl_key_size  (byte)(int)      via JkOptions +ForwardKeySize
413     request_terminator (byte)
414     ?body          content_length*(var binary)
415
416  */
417
418 static int ajp_marshal_into_msgb(jk_msg_buf_t *msg,
419                                  jk_ws_service_t *s,
420                                  jk_logger_t *l, ajp_endpoint_t * ae)
421 {
422     int method;
423     unsigned int i;
424
425     JK_TRACE_ENTER(l);
426
427     if ((method = sc_for_req_method(s->method,
428                                     strlen(s->method))) == UNKNOWN_METHOD)
429         method = SC_M_JK_STORED;
430
431     if (jk_b_append_byte(msg, JK_AJP13_FORWARD_REQUEST) ||
432         jk_b_append_byte(msg, (unsigned char)method) ||
433         jk_b_append_string(msg, s->protocol) ||
434         jk_b_append_string(msg, s->req_uri) ||
435         jk_b_append_string(msg, s->remote_addr) ||
436         jk_b_append_string(msg, s->remote_host) ||
437         jk_b_append_string(msg, s->server_name) ||
438         jk_b_append_int(msg, (unsigned short)s->server_port) ||
439         jk_b_append_byte(msg, (unsigned char)(s->is_ssl)) ||
440         jk_b_append_int(msg, (unsigned short)(s->num_headers))) {
441
442         jk_log(l, JK_LOG_ERROR,
443                "failed appending the message begining");
444         JK_TRACE_EXIT(l);
445         return JK_FALSE;
446     }
447
448     for (i = 0; i < s->num_headers; i++) {
449         int sc;
450
451         if ((sc = sc_for_req_header(s->headers_names[i])) != UNKNOWN_METHOD) {
452             if (jk_b_append_int(msg, (unsigned short)sc)) {
453                 jk_log(l, JK_LOG_ERROR,
454                        "failed appending the header name");
455                 JK_TRACE_EXIT(l);
456                 return JK_FALSE;
457             }
458         }
459         else {
460             if (jk_b_append_string(msg, s->headers_names[i])) {
461                 jk_log(l, JK_LOG_ERROR,
462                        "failed appending the header name");
463                 JK_TRACE_EXIT(l);
464                 return JK_FALSE;
465             }
466         }
467
468         if (jk_b_append_string(msg, s->headers_values[i])) {
469             jk_log(l, JK_LOG_ERROR,
470                    "failed appending the header value");
471             JK_TRACE_EXIT(l);
472             return JK_FALSE;
473         }
474     }
475
476     if (s->secret) {
477         if (jk_b_append_byte(msg, SC_A_SECRET) ||
478             jk_b_append_string(msg, s->secret)) {
479             jk_log(l, JK_LOG_ERROR,
480                    "failed appending secret");
481             JK_TRACE_EXIT(l);
482             return JK_FALSE;
483         }
484     }
485
486     if (s->remote_user) {
487         if (jk_b_append_byte(msg, SC_A_REMOTE_USER) ||
488             jk_b_append_string(msg, s->remote_user)) {
489             jk_log(l, JK_LOG_ERROR,
490                    "failed appending the remote user");
491             JK_TRACE_EXIT(l);
492             return JK_FALSE;
493         }
494     }
495     if (s->auth_type) {
496         if (jk_b_append_byte(msg, SC_A_AUTH_TYPE) ||
497             jk_b_append_string(msg, s->auth_type)) {
498             jk_log(l, JK_LOG_ERROR,
499                    "failed appending the auth type");
500             JK_TRACE_EXIT(l);
501             return JK_FALSE;
502         }
503     }
504     if (s->query_string) {
505         if (jk_b_append_byte(msg, SC_A_QUERY_STRING) ||
506 #if defined(AS400) && !defined(AS400_UTF8)
507             jk_b_append_asciistring(msg, s->query_string)) {
508 #else
509             jk_b_append_string(msg, s->query_string)) {
510 #endif
511             jk_log(l, JK_LOG_ERROR,
512                    "failed appending the query string");
513             JK_TRACE_EXIT(l);
514             return JK_FALSE;
515         }
516     }
517     if (s->route) {
518         if (jk_b_append_byte(msg, SC_A_ROUTE) ||
519             jk_b_append_string(msg, s->route)) {
520             jk_log(l, JK_LOG_ERROR,
521                    "failed appending the route");
522             JK_TRACE_EXIT(l);
523             return JK_FALSE;
524         }
525     }
526     if (s->ssl_cert_len) {
527         if (jk_b_append_byte(msg, SC_A_SSL_CERT) ||
528             jk_b_append_string(msg, s->ssl_cert)) {
529             jk_log(l, JK_LOG_ERROR,
530                    "failed appending the SSL certificates");
531             JK_TRACE_EXIT(l);
532             return JK_FALSE;
533         }
534     }
535
536     if (s->ssl_cipher) {
537         if (jk_b_append_byte(msg, SC_A_SSL_CIPHER) ||
538             jk_b_append_string(msg, s->ssl_cipher)) {
539             jk_log(l, JK_LOG_ERROR,
540                    "failed appending the SSL ciphers");
541             JK_TRACE_EXIT(l);
542             return JK_FALSE;
543         }
544     }
545     if (s->ssl_session) {
546         if (jk_b_append_byte(msg, SC_A_SSL_SESSION) ||
547             jk_b_append_string(msg, s->ssl_session)) {
548             jk_log(l, JK_LOG_ERROR,
549                    "failed appending the SSL session");
550             JK_TRACE_EXIT(l);
551             return JK_FALSE;
552         }
553     }
554
555     /*
556      * ssl_key_size is required by Servlet 2.3 API
557      * added support only in ajp14 mode
558      * JFC removed: ae->proto == AJP14_PROTO
559      */
560     if (s->ssl_key_size != -1) {
561         if (jk_b_append_byte(msg, SC_A_SSL_KEY_SIZE) ||
562             jk_b_append_int(msg, (unsigned short)s->ssl_key_size)) {
563             jk_log(l, JK_LOG_ERROR,
564                    "failed appending the SSL key size");
565             JK_TRACE_EXIT(l);
566             return JK_FALSE;
567         }
568     }
569
570     /* If the method was unrecognized, encode it as an attribute */
571     if (method == SC_M_JK_STORED) {
572         if (JK_IS_DEBUG_LEVEL(l))
573             jk_log(l, JK_LOG_DEBUG, "unknown method %s", s->method);
574         if (jk_b_append_byte(msg, SC_A_STORED_METHOD) ||
575             jk_b_append_string(msg, s->method)) {
576             jk_log(l, JK_LOG_ERROR,
577                    "failed appending the request method");
578             JK_TRACE_EXIT(l);
579             return JK_FALSE;
580         }
581     }
582
583     /* Forward the remote port information, which was forgotten
584      * from the builtin data of the AJP 13 protocol.
585      * Since the servlet spec allows to retrieve it via getRemotePort(),
586      * we provide the port to the Tomcat connector as a request
587      * attribute. Modern Tomcat versions know how to retrieve
588      * the remote port from this attribute.
589      */
590     {
591         if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) ||
592             jk_b_append_string(msg, SC_A_REQ_REMOTE_PORT)   ||
593             jk_b_append_string(msg, s->remote_port)) {
594             jk_log(l, JK_LOG_ERROR,
595                    "failed appending the remote port %s",
596                    s->remote_port);
597             JK_TRACE_EXIT(l);
598             return JK_FALSE;
599         }
600     }
601
602     /* Forward activation information from the load balancer.
603      * It can be used by the backend to deny access by requests,
604      * which come with a session id but for an invalid session.
605      * Such requests get forwarded to backends even if they
606      * are disabled" in the load balancer, because the balancer
607      * does not know, which sessions are valid.
608      * If the backend can check, that is was "disabled" it can
609      * delete the session cookie and respond with a self-referential
610      * redirect. The new request will then be balanced to some
611      * other node that is not disabled.
612      */
613     {
614         if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) ||
615             jk_b_append_string(msg, SC_A_JK_LB_ACTIVATION)   ||
616             jk_b_append_string(msg, s->activation)) {
617             jk_log(l, JK_LOG_ERROR,
618                    "failed appending the activation state %s",
619                    s->activation);
620             JK_TRACE_EXIT(l);
621             return JK_FALSE;
622         }
623     }
624
625     if (s->num_attributes > 0) {
626         for (i = 0; i < s->num_attributes; i++) {
627             if (jk_b_append_byte(msg, SC_A_REQ_ATTRIBUTE) ||
628                 jk_b_append_string(msg, s->attributes_names[i]) ||
629                 jk_b_append_string(msg, s->attributes_values[i])) {
630                 jk_log(l, JK_LOG_ERROR,
631                        "failed appending attribute %s=%s",
632                        s->attributes_names[i], s->attributes_values[i]);
633                 JK_TRACE_EXIT(l);
634                 return JK_FALSE;
635             }
636         }
637     }
638
639     if (jk_b_append_byte(msg, SC_A_ARE_DONE)) {
640         jk_log(l, JK_LOG_ERROR,
641                "failed appending the message end");
642         JK_TRACE_EXIT(l);
643         return JK_FALSE;
644     }
645
646     if (JK_IS_DEBUG_LEVEL(l))
647         jk_log(l, JK_LOG_DEBUG, "ajp marshaling done");
648     JK_TRACE_EXIT(l);
649     return JK_TRUE;
650 }
651
652 /*
653 AJPV13_RESPONSE/AJPV14_RESPONSE:=
654     response_prefix (2)
655     status          (short)
656     status_msg      (short)
657     num_headers     (short)
658     num_headers*(res_header_name header_value)
659     *body_chunk
660     terminator      boolean <! -- recycle connection or not  -->
661
662 req_header_name :=
663     sc_req_header_name | (string)
664
665 res_header_name :=
666     sc_res_header_name | (string)
667
668 header_value :=
669     (string)
670
671 body_chunk :=
672     length  (short)
673     body    length*(var binary)
674
675  */
676
677
678 static int ajp_unmarshal_response(jk_msg_buf_t *msg,
679                                   jk_res_data_t * d,
680                                   ajp_endpoint_t * ae, jk_logger_t *l)
681 {
682     jk_pool_t *p = &ae->pool;
683
684     JK_TRACE_ENTER(l);
685
686     d->status = jk_b_get_int(msg);
687     if (!d->status) {
688         jk_log(l, JK_LOG_ERROR,
689                "NULL status");
690         JK_TRACE_EXIT(l);
691         return JK_FALSE;
692     }
693
694     d->msg = (char *)jk_b_get_string(msg);
695     if (d->msg) {
696 #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX)
697         jk_xlate_from_ascii(d->msg, strlen(d->msg));
698 #endif
699     }
700
701     if (JK_IS_DEBUG_LEVEL(l))
702         jk_log(l, JK_LOG_DEBUG,
703                "status = %d", d->status);
704
705     d->num_headers = jk_b_get_int(msg);
706     d->header_names = d->header_values = NULL;
707
708     if (JK_IS_DEBUG_LEVEL(l))
709         jk_log(l, JK_LOG_DEBUG,
710                "Number of headers is = %d",
711                d->num_headers);
712
713     if (d->num_headers) {
714         d->header_names = jk_pool_alloc(p, sizeof(char *) * d->num_headers);
715         d->header_values = jk_pool_alloc(p, sizeof(char *) * d->num_headers);
716
717         if (d->header_names && d->header_values) {
718             unsigned int i;
719             for (i = 0; i < d->num_headers; i++) {
720                 unsigned short name = jk_b_pget_int(msg, msg->pos);
721
722                 if ((name & 0XFF00) == 0XA000) {
723                     jk_b_get_int(msg);
724                     name = name & 0X00FF;
725                     if (name <= SC_RES_HEADERS_NUM) {
726                         d->header_names[i] =
727                             (char *)long_res_header_for_sc(name);
728                     }
729                     else {
730                         jk_log(l, JK_LOG_ERROR,
731                                "No such sc (%d)", name);
732                         JK_TRACE_EXIT(l);
733                         return JK_FALSE;
734                     }
735                 }
736                 else {
737                     d->header_names[i] = (char *)jk_b_get_string(msg);
738                     if (!d->header_names[i]) {
739                         jk_log(l, JK_LOG_ERROR,
740                                "NULL header name");
741                         JK_TRACE_EXIT(l);
742                         return JK_FALSE;
743                     }
744 #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX)
745                     jk_xlate_from_ascii(d->header_names[i],
746                                         strlen(d->header_names[i]));
747 #endif
748
749                 }
750
751                 d->header_values[i] = (char *)jk_b_get_string(msg);
752                 if (!d->header_values[i]) {
753                     jk_log(l, JK_LOG_ERROR,
754                            "NULL header value");
755                     JK_TRACE_EXIT(l);
756                     return JK_FALSE;
757                 }
758
759 #if (defined(AS400) && !defined(AS400_UTF8)) || defined(_OSD_POSIX)
760                 jk_xlate_from_ascii(d->header_values[i],
761                                     strlen(d->header_values[i]));
762 #endif
763
764                 if (JK_IS_DEBUG_LEVEL(l))
765                     jk_log(l, JK_LOG_DEBUG,
766                            "Header[%d] [%s] = [%s]",
767                            i, d->header_names[i], d->header_values[i]);
768             }
769         }
770     }
771
772     JK_TRACE_EXIT(l);
773     return JK_TRUE;
774 }
775
776 /*
777  * Abort endpoint use
778  */
779 static void ajp_abort_endpoint(ajp_endpoint_t * ae, int shutdown, jk_logger_t *l)
780 {
781     JK_TRACE_ENTER(l);
782     if (shutdown == JK_TRUE && IS_VALID_SOCKET(ae->sd)) {
783         if (ae->hard_close) {
784             /* Force unclean connection close to communicate client write errors
785              * back to Tomcat by aborting AJP response writes.
786              */
787             jk_close_socket(ae->sd, l);
788         }
789         else {
790             jk_shutdown_socket(ae->sd, l);
791         }
792     }
793     ae->worker->s->connected--;
794     ae->sd = JK_INVALID_SOCKET;
795     ae->last_op = JK_AJP13_END_RESPONSE;
796     JK_TRACE_EXIT(l);
797 }
798
799 /*
800  * Reset the endpoint (clean buf and close socket)
801  */
802 static void ajp_reset_endpoint(ajp_endpoint_t * ae, jk_logger_t *l)
803 {
804     JK_TRACE_ENTER(l);
805
806     if (JK_IS_DEBUG_LEVEL(l))
807         jk_log(l, JK_LOG_DEBUG,
808         "(%s) resetting endpoint with socket %d%s",
809          ae->worker->name, ae->sd, ae->reuse? "" : " (socket shutdown)");
810     if (!ae->reuse) {
811         ajp_abort_endpoint(ae, JK_TRUE, l);
812     }
813     jk_reset_pool(&(ae->pool));
814     JK_TRACE_EXIT(l);
815 }
816
817 /*
818  * Close the endpoint (close pool and close socket)
819  */
820 void ajp_close_endpoint(ajp_endpoint_t * ae, jk_logger_t *l)
821 {
822     JK_TRACE_ENTER(l);
823
824     if (JK_IS_DEBUG_LEVEL(l))
825         jk_log(l, JK_LOG_DEBUG,
826                "(%s) closing endpoint with socket %d%s",
827                ae->worker->name, ae->sd, ae->reuse ? "" : " (socket shutdown)");
828     if (IS_VALID_SOCKET(ae->sd)) {
829         jk_shutdown_socket(ae->sd, l);
830     }
831     ae->sd = JK_INVALID_SOCKET;
832     jk_close_pool(&(ae->pool));
833     free(ae);
834     JK_TRACE_EXIT(l);
835 }
836
837
838 /** Steal a connection from an idle cache endpoint
839  * @param ae   endpoint that needs a new connection
840  * @param l    logger
841  * @return     JK_FALSE: failure
842  *             JK_TRUE: success
843  * @remark     Always closes old socket endpoint
844  */
845 static int ajp_next_connection(ajp_endpoint_t *ae, jk_logger_t *l)
846 {
847     int rc;
848     int ret = JK_FALSE;
849     ajp_worker_t *aw = ae->worker;
850
851     JK_TRACE_ENTER(l);
852
853     /* Close previous socket */
854     if (IS_VALID_SOCKET(ae->sd))
855         jk_shutdown_socket(ae->sd, l);
856     /* Mark existing endpoint socket as closed */
857     ae->sd = JK_INVALID_SOCKET;
858     JK_ENTER_CS(&aw->cs, rc);
859     if (rc) {
860         unsigned int i;
861         for (i = 0; i < aw->ep_cache_sz; i++) {
862             /* Find cache slot with usable socket */
863             if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) {
864                 ae->sd = aw->ep_cache[i]->sd;
865                 aw->ep_cache[i]->sd = JK_INVALID_SOCKET;
866                 break;
867             }
868         }
869         JK_LEAVE_CS(&aw->cs, rc);
870         if (IS_VALID_SOCKET(ae->sd)) {
871             ret = JK_TRUE;
872             if (JK_IS_DEBUG_LEVEL(l))
873                 jk_log(l, JK_LOG_DEBUG,
874                        "(%s) Will try pooled connection socket %d from slot %d",
875                         ae->worker->name, ae->sd, i);
876         }
877     }
878     JK_TRACE_EXIT(l);
879     return ret;
880 }
881
882 /** Handle the cping/cpong query
883  * @param ae       endpoint
884  * @param timeout  wait timeout in milliseconds
885  * @param l        logger
886  * @return         JK_FALSE: failure
887  *                 JK_TRUE: success
888  * @remark         Always closes socket in case of
889  *                 a socket error
890  */
891 static int ajp_handle_cping_cpong(ajp_endpoint_t * ae, int timeout, jk_logger_t *l)
892 {
893     int i;
894     int cmd;
895     jk_msg_buf_t *msg;
896
897     JK_TRACE_ENTER(l);
898
899     ae->last_errno = 0;
900     msg = jk_b_new(&ae->pool);
901     if (!msg) {
902         jk_log(l, JK_LOG_ERROR,
903                "Failed allocating AJP message");
904         JK_TRACE_EXIT(l);
905         return JK_FALSE;
906     }
907     if (jk_b_set_buffer_size(msg, 16)) {
908         jk_log(l, JK_LOG_ERROR,
909                "Failed allocating AJP message buffer");
910         JK_TRACE_EXIT(l);
911         return JK_FALSE;
912     }
913     jk_b_reset(msg);
914     jk_b_append_byte(msg, AJP13_CPING_REQUEST);
915
916     /* Send CPing query */
917     if (ajp_connection_tcp_send_message(ae, msg, l) != JK_TRUE) {
918         jk_log(l, JK_LOG_INFO,
919                "can't send cping query");
920         JK_TRACE_EXIT(l);
921         return JK_FALSE;
922     }
923
924     for (i = 0; i < 2; i++) {
925         /* wait for Pong reply for timeout milliseconds
926          */
927         if (jk_is_input_event(ae->sd, timeout, l) == JK_FALSE) {
928             ae->last_errno = errno;
929             jk_log(l, JK_LOG_INFO, "timeout in reply cpong");
930             /* We can't trust this connection any more. */
931             ajp_abort_endpoint(ae, JK_TRUE, l);
932             JK_TRACE_EXIT(l);
933             return JK_FALSE;
934         }
935
936         /* Read and check for Pong reply
937          */
938         if (ajp_connection_tcp_get_message(ae, msg, l) != JK_TRUE) {
939             jk_log(l, JK_LOG_INFO,
940                    "awaited reply cpong, not received");
941             JK_TRACE_EXIT(l);
942             return JK_FALSE;
943         }
944
945         if ((cmd = jk_b_get_byte(msg)) != AJP13_CPONG_REPLY) {
946             /* If the respose was not CPONG it means that
947              * the previous response was not consumed by the
948              * client but the AJP messages was already in
949              * the network buffer.
950              * silently drop this single extra packet instead
951              * recycling the connection
952              */
953             if (i || ae->last_op == JK_AJP13_END_RESPONSE ||
954                      cmd < JK_AJP13_SEND_BODY_CHUNK ||
955                      cmd > AJP13_CPONG_REPLY) {
956                 jk_log(l, JK_LOG_WARNING,
957                        "awaited reply cpong, received %d instead. "
958                        "Closing connection",
959                        cmd);
960                 /* We can't trust this connection any more. */
961                 ajp_abort_endpoint(ae, JK_TRUE, l);
962                 JK_TRACE_EXIT(l);
963                 return JK_FALSE;
964             }
965             else {
966                 jk_log(l, JK_LOG_INFO,
967                        "awaited reply cpong, received %d instead. "
968                        "Retrying next packet",
969                        cmd);
970
971             }
972         }
973         else {
974             ae->last_op = AJP13_CPONG_REPLY;
975             /* We have received Pong reply */
976             break;
977         }
978     }
979     JK_TRACE_EXIT(l);
980     return JK_TRUE;
981 }
982
983 /** Connect an endpoint to a backend
984  * @param ae       endpoint
985  * @param l        logger
986  * @return         JK_FALSE: failure
987  *                 JK_TRUE: success
988  * @remark         Always closes socket in case of
989  *                 a socket error
990  * @remark         Cares about ae->last_errno
991  */
992 int ajp_connect_to_endpoint(ajp_endpoint_t * ae, jk_logger_t *l)
993 {
994     char buf[32];
995     int rc = JK_TRUE;
996
997     JK_TRACE_ENTER(l);
998
999     ae->last_errno = 0;
1000     ae->sd = jk_open_socket(&ae->worker->worker_inet_addr,
1001                             ae->worker->keepalive,
1002                             ae->worker->socket_timeout,
1003                             ae->worker->socket_connect_timeout,
1004                             ae->worker->socket_buf, l);
1005
1006     if (!IS_VALID_SOCKET(ae->sd)) {
1007         ae->last_errno = errno;
1008         jk_log(l, JK_LOG_INFO,
1009                "Failed opening socket to (%s) (errno=%d)",
1010                jk_dump_hinfo(&ae->worker->worker_inet_addr, buf), ae->last_errno);
1011         JK_TRACE_EXIT(l);
1012         return JK_FALSE;
1013     }
1014     ae->worker->s->connected++;
1015     /* set last_access only if needed */
1016     if (ae->worker->cache_timeout > 0)
1017         ae->last_access = time(NULL);
1018     /* Check if we must execute a logon after the physical connect */
1019     /* XXX: Not sure, if we really should do logon before cping/cpong */
1020     /* XXX: and if no cping/cpong is allowed before or after logon. */
1021     if (ae->worker->logon != NULL) {
1022         rc = ae->worker->logon(ae, l);
1023         if (rc == JK_FALSE) {
1024             jk_log(l, JK_LOG_ERROR,
1025                    "(%s) ajp14 worker logon to the backend server failed",
1026                    ae->worker->name);
1027             /* Close the socket if unable to logon */
1028             ajp_abort_endpoint(ae, JK_TRUE, l);
1029         }
1030     }
1031     /* XXX: Should we send a cping also after logon to validate the connection? */
1032     else if (ae->worker->connect_timeout > 0) {
1033         rc = ajp_handle_cping_cpong(ae, ae->worker->connect_timeout, l);
1034         if (rc == JK_FALSE)
1035             jk_log(l, JK_LOG_ERROR,
1036                    "(%s) cping/cpong after connecting to the backend server failed (errno=%d)",
1037                    ae->worker->name, ae->last_errno);
1038     }
1039     JK_TRACE_EXIT(l);
1040     return rc;
1041 }
1042
1043 /* Syncing config values from shm */
1044 void jk_ajp_pull(ajp_worker_t * aw, int locked, jk_logger_t *l)
1045 {
1046     int address_change = JK_FALSE;
1047     int port = 0;
1048     char host[JK_SHM_STR_SIZ+1];
1049     struct sockaddr_in inet_addr;
1050     JK_TRACE_ENTER(l);
1051
1052     if (JK_IS_DEBUG_LEVEL(l))
1053         jk_log(l, JK_LOG_DEBUG,
1054                "syncing mem for ajp worker '%s' from shm (%u -> %u) [%u->%u]",
1055                aw->name, aw->sequence, aw->s->h.sequence, aw->addr_sequence, aw->s->addr_sequence);
1056     if (locked == JK_FALSE)
1057         jk_shm_lock();
1058
1059     aw->cache_timeout = aw->s->cache_timeout;
1060     aw->connect_timeout = aw->s->connect_timeout;
1061     aw->ping_timeout = aw->s->ping_timeout;
1062     aw->reply_timeout = aw->s->reply_timeout;
1063     aw->prepost_timeout = aw->s->prepost_timeout;
1064     aw->recovery_opts = aw->s->recovery_opts;
1065     aw->retries = aw->s->retries;
1066     aw->retry_interval = aw->s->retry_interval;
1067     aw->max_packet_size = aw->s->max_packet_size;
1068     aw->sequence = aw->s->h.sequence;
1069     if (aw->addr_sequence != aw->s->addr_sequence) {
1070         address_change = JK_TRUE;
1071         aw->addr_sequence = aw->s->addr_sequence;
1072         strncpy(host, aw->s->host, JK_SHM_STR_SIZ);
1073         port = aw->s->port;
1074     }
1075     if (locked == JK_FALSE)
1076         jk_shm_unlock();
1077
1078     if (address_change == JK_TRUE) {
1079         if (!jk_resolve(host, port, &inet_addr,
1080                         aw->worker.we->pool, l)) {
1081             jk_log(l, JK_LOG_ERROR,
1082                    "Failed resolving address '%s:%d' for worker '%s'.",
1083                    host, port, aw->name);
1084         }
1085         else {
1086             int rc;
1087             JK_ENTER_CS(&aw->cs, rc);
1088             if (rc) {
1089                 unsigned int i;
1090                 for (i = 0; i < aw->ep_cache_sz; i++) {
1091                     /* Close all connections in the cache */
1092                     if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) {
1093                         int sd = aw->ep_cache[i]->sd;
1094                         aw->ep_cache[i]->sd = JK_INVALID_SOCKET;
1095                         aw->ep_cache[i]->addr_sequence = aw->addr_sequence;
1096                         jk_shutdown_socket(sd, l);
1097                         aw->s->connected--;
1098                     }
1099                 }
1100             }
1101             aw->port = port;
1102             strncpy(aw->host, host, JK_SHM_STR_SIZ);
1103             memcpy(&(aw->worker_inet_addr), &inet_addr, sizeof(inet_addr));
1104             if (rc) {
1105                 JK_LEAVE_CS(&aw->cs, rc);
1106             } else {
1107                 jk_log(l, JK_LOG_ERROR,
1108                        "locking thread (errno=%d)", errno);
1109             }
1110         }
1111     }
1112
1113     JK_TRACE_EXIT(l);
1114 }
1115
1116 /* Syncing config values to shm */
1117 void jk_ajp_push(ajp_worker_t * aw, int locked, jk_logger_t *l)
1118 {
1119     int address_change = JK_FALSE;
1120
1121     JK_TRACE_ENTER(l);
1122
1123     if (JK_IS_DEBUG_LEVEL(l))
1124         jk_log(l, JK_LOG_DEBUG,
1125                "syncing shm for ajp worker '%s' from mem (%u -> %u) [%u->%u]",
1126                aw->name, aw->s->h.sequence, aw->sequence, aw->s->addr_sequence, aw->addr_sequence);
1127     if (locked == JK_FALSE)
1128         jk_shm_lock();
1129
1130     aw->s->cache_timeout = aw->cache_timeout;
1131     aw->s->connect_timeout = aw->connect_timeout;
1132     aw->s->ping_timeout = aw->ping_timeout;
1133     aw->s->reply_timeout = aw->reply_timeout;
1134     aw->s->prepost_timeout = aw->prepost_timeout;
1135     aw->s->recovery_opts = aw->recovery_opts;
1136     aw->s->retries = aw->retries;
1137     aw->s->retry_interval = aw->retry_interval;
1138     aw->s->max_packet_size = aw->max_packet_size;
1139     aw->s->h.sequence = aw->sequence;
1140     if (aw->s->addr_sequence != aw->addr_sequence) {
1141         address_change = JK_TRUE;
1142         strncpy(aw->s->host, aw->host, JK_SHM_STR_SIZ);
1143         aw->s->port = aw->port;
1144         aw->s->addr_sequence = aw->addr_sequence;
1145     }
1146     if (locked == JK_FALSE)
1147         jk_shm_unlock();
1148
1149     if (address_change == JK_TRUE) {
1150         int rc;
1151         JK_ENTER_CS(&aw->cs, rc);
1152         if (rc) {
1153             unsigned int i;
1154             for (i = 0; i < aw->ep_cache_sz; i++) {
1155                 /* Close all connections in the cache */
1156                 if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) {
1157                     int sd = aw->ep_cache[i]->sd;
1158                     aw->ep_cache[i]->sd = JK_INVALID_SOCKET;
1159                     aw->ep_cache[i]->addr_sequence = aw->addr_sequence;
1160                     jk_shutdown_socket(sd, l);
1161                     aw->s->connected--;
1162                 }
1163             }
1164             JK_LEAVE_CS(&aw->cs, rc);
1165         } else {
1166             jk_log(l, JK_LOG_ERROR,
1167                    "locking thread (errno=%d)", errno);
1168         }
1169     }
1170     JK_TRACE_EXIT(l);
1171 }
1172
1173 /** Send a message to an endpoint, using corresponding PROTO HEADER
1174  * @param ae       endpoint
1175  * @param msg      message to send
1176  * @param l        logger
1177  * @return         JK_FATAL_ERROR: endpoint contains unknown protocol
1178  *                 JK_FALSE: other failure
1179  *                 JK_TRUE: success
1180  * @remark         Always closes socket in case of
1181  *                 a socket error, or JK_FATAL_ERROR
1182  * @remark         Cares about ae->last_errno
1183  */
1184 int ajp_connection_tcp_send_message(ajp_endpoint_t * ae,
1185                                     jk_msg_buf_t *msg, jk_logger_t *l)
1186 {
1187     int rc;
1188
1189     JK_TRACE_ENTER(l);
1190
1191     ae->last_errno = 0;
1192     if (ae->proto == AJP13_PROTO) {
1193         jk_b_end(msg, AJP13_WS_HEADER);
1194         if (JK_IS_DEBUG_LEVEL(l))
1195             jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp13", msg);
1196     }
1197     else if (ae->proto == AJP14_PROTO) {
1198         jk_b_end(msg, AJP14_WS_HEADER);
1199         if (JK_IS_DEBUG_LEVEL(l))
1200             jk_dump_buff(l, JK_LOG_DEBUG, "sending to ajp14", msg);
1201     }
1202     else {
1203         jk_log(l, JK_LOG_ERROR,
1204                "(%s) unknown protocol %d, supported are AJP13/AJP14",
1205                 ae->worker->name, ae->proto);
1206         /* We've got a protocol error. */
1207         /* We can't trust this connection any more, */
1208         /* because we might have send already parts of the request. */
1209         ajp_abort_endpoint(ae, JK_TRUE, l);
1210         JK_TRACE_EXIT(l);
1211         return JK_FATAL_ERROR;
1212     }
1213
1214     /* This is the only place in this function where we use the socket. */
1215     /* If sendfull gets an error, it implicitely closes the socket. */
1216     /* So any socket error inside ajp_connection_tcp_send_message */
1217     /* results in a socket close and invalidated endpoint connection. */
1218     if ((rc = jk_tcp_socket_sendfull(ae->sd, msg->buf,
1219                                      msg->len, l)) > 0) {
1220         ae->endpoint.wr += (jk_uint64_t)rc;
1221         JK_TRACE_EXIT(l);
1222         return JK_TRUE;
1223     }
1224     ae->last_errno = errno;
1225     jk_log(l, JK_LOG_INFO,
1226            "sendfull for socket %d returned %d (errno=%d)",
1227            ae->sd, rc, ae->last_errno);
1228     ajp_abort_endpoint(ae, JK_FALSE, l);
1229     JK_TRACE_EXIT(l);
1230     return JK_FALSE;
1231 }
1232
1233 /** Receive a message from an endpoint, checking PROTO HEADER
1234  * @param ae       endpoint
1235  * @param msg      message to send
1236  * @param l        logger
1237  * @return         JK_TRUE: success
1238  *                 JK_FALSE: could not read the AJP packet header
1239  *                 JK_AJP_PROTOCOL_ERROR: failure after reading
1240  *                 the AJP packet header
1241  * @remark         Always closes socket in case of
1242  *                 a socket error
1243  * @remark         Cares about ae->last_errno
1244  */
1245 int ajp_connection_tcp_get_message(ajp_endpoint_t * ae,
1246                                    jk_msg_buf_t *msg, jk_logger_t *l)
1247 {
1248     unsigned char head[AJP_HEADER_LEN];
1249     int rc;
1250     int msglen;
1251     unsigned int header;
1252     char buf[32];
1253
1254     JK_TRACE_ENTER(l);
1255
1256     ae->last_errno = 0;
1257     /* If recvfull gets an error, it implicitely closes the socket. */
1258     /* We will invalidate the endpoint connection. */
1259     rc = jk_tcp_socket_recvfull(ae->sd, head, AJP_HEADER_LEN, l);
1260
1261     /* If the return code is not negative */
1262     /* then we always get back the correct number of bytes. */
1263     if (rc < 0) {
1264         if (rc == JK_SOCKET_EOF) {
1265             ae->last_errno = EPIPE;
1266             jk_log(l, JK_LOG_INFO,
1267                    "(%s) can't receive the response header message from tomcat, "
1268                    "tomcat (%s) has forced a connection close for socket %d",
1269                    ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf),
1270                    ae->sd);
1271         }
1272         else {
1273             ae->last_errno = -rc;
1274             jk_log(l, JK_LOG_INFO,
1275                    "(%s) can't receive the response header message from tomcat, "
1276                    "network problems or tomcat (%s) is down (errno=%d)",
1277                    ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf),
1278                    ae->last_errno);
1279         }
1280         ajp_abort_endpoint(ae, JK_FALSE, l);
1281         JK_TRACE_EXIT(l);
1282         return JK_FALSE;
1283     }
1284     ae->endpoint.rd += (jk_uint64_t)rc;
1285     header = ((unsigned int)head[0] << 8) | head[1];
1286
1287     if (ae->proto == AJP13_PROTO) {
1288         if (header != AJP13_SW_HEADER) {
1289
1290             if (header == AJP14_SW_HEADER) {
1291                 jk_log(l, JK_LOG_ERROR,
1292                        "received AJP14 reply on an AJP13 connection from %s",
1293                        jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
1294             }
1295             else {
1296                 jk_log(l, JK_LOG_ERROR,
1297                        "wrong message format 0x%04x from %s",
1298                        header, jk_dump_hinfo(&ae->worker->worker_inet_addr,
1299                                              buf));
1300             }
1301             /* We've got a protocol error. */
1302             /* We can't trust this connection any more. */
1303             ajp_abort_endpoint(ae, JK_TRUE, l);
1304             JK_TRACE_EXIT(l);
1305             return JK_AJP_PROTOCOL_ERROR;
1306         }
1307     }
1308     else if (ae->proto == AJP14_PROTO) {
1309         if (header != AJP14_SW_HEADER) {
1310
1311             if (header == AJP13_SW_HEADER) {
1312                 jk_log(l, JK_LOG_ERROR,
1313                        "received AJP13 reply on an AJP14 connection from %s",
1314                        jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
1315             }
1316             else {
1317                 jk_log(l, JK_LOG_ERROR,
1318                        "wrong message format 0x%04x from %s",
1319                        header, jk_dump_hinfo(&ae->worker->worker_inet_addr,
1320                                              buf));
1321             }
1322             /* We've got a protocol error. */
1323             /* We can't trust this connection any more. */
1324             ajp_abort_endpoint(ae, JK_TRUE, l);
1325             JK_TRACE_EXIT(l);
1326             return JK_AJP_PROTOCOL_ERROR;
1327         }
1328     }
1329
1330     msglen = ((head[2] & 0xff) << 8);
1331     msglen += (head[3] & 0xFF);
1332
1333     if (msglen > msg->maxlen) {
1334         jk_log(l, JK_LOG_ERROR,
1335                "wrong message size %d %d from %s",
1336                msglen, msg->maxlen,
1337                jk_dump_hinfo(&ae->worker->worker_inet_addr, buf));
1338         /* We've got a protocol error. */
1339         /* We can't trust this connection any more. */
1340         ajp_abort_endpoint(ae, JK_TRUE, l);
1341         JK_TRACE_EXIT(l);
1342         return JK_AJP_PROTOCOL_ERROR;
1343     }
1344
1345     msg->len = msglen;
1346     msg->pos = 0;
1347
1348     /* If recvfull gets an error, it implicitely closes the socket. */
1349     /* We will invalidate the endpoint connection. */
1350     rc = jk_tcp_socket_recvfull(ae->sd, msg->buf, msglen, l);
1351     /* If the return code is not negative */
1352     /* then we always get back the correct number of bytes. */
1353     if (rc < 0) {
1354         if (rc == JK_SOCKET_EOF) {
1355             ae->last_errno = EPIPE;
1356             jk_log(l, JK_LOG_ERROR,
1357                    "(%s) can't receive the response body message from tomcat, "
1358                    "tomcat (%s) has forced a connection close for socket %d",
1359                    ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf),
1360                    ae->sd);
1361         }
1362         else {
1363             ae->last_errno = -rc;
1364             jk_log(l, JK_LOG_ERROR,
1365                    "(%s) can't receive the response body message from tomcat, "
1366                    "network problems or tomcat (%s) is down (errno=%d)",
1367                    ae->worker->name, jk_dump_hinfo(&ae->worker->worker_inet_addr, buf),
1368                    ae->last_errno);
1369         }
1370         ajp_abort_endpoint(ae, JK_FALSE, l);
1371         JK_TRACE_EXIT(l);
1372         /* Although we have a connection, this is effectively a protocol error.
1373          * We received the AJP header packet, but not the packet payload
1374          */
1375         return JK_AJP_PROTOCOL_ERROR;
1376     }
1377     ae->endpoint.rd += (jk_uint64_t)rc;
1378
1379     if (JK_IS_DEBUG_LEVEL(l)) {
1380         if (ae->proto == AJP13_PROTO)
1381             jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp13", msg);
1382         else if (ae->proto == AJP14_PROTO)
1383             jk_dump_buff(l, JK_LOG_DEBUG, "received from ajp14", msg);
1384     }
1385     JK_TRACE_EXIT(l);
1386     return JK_TRUE;
1387 }
1388
1389 /*
1390  * Read all the data from the socket.
1391  *
1392  * Socket API doesn't guaranty that all the data will be kept in a
1393  * single read, so we must loop until all awaited data is received
1394  */
1395
1396 static int ajp_read_fully_from_server(jk_ws_service_t *s, jk_logger_t *l,
1397                                       unsigned char *buf, unsigned int len)
1398 {
1399     unsigned int rdlen = 0;
1400     unsigned int padded_len = len;
1401
1402     JK_TRACE_ENTER(l);
1403
1404     if (s->is_chunked && s->no_more_chunks) {
1405         JK_TRACE_EXIT(l);
1406         return 0;
1407     }
1408     if (s->is_chunked) {
1409         /* Corner case: buf must be large enough to hold next
1410          * chunk size (if we're on or near a chunk border).
1411          * Pad the length to a reasonable value, otherwise the
1412          * read fails and the remaining chunks are tossed.
1413          */
1414         padded_len = (len < CHUNK_BUFFER_PAD) ? len : len - CHUNK_BUFFER_PAD;
1415     }
1416
1417     while (rdlen < padded_len) {
1418         unsigned int this_time = 0;
1419         if (!s->read(s, buf + rdlen, len - rdlen, &this_time)) {
1420             /* Remote Client read failed. */
1421             JK_TRACE_EXIT(l);
1422             return JK_CLIENT_RD_ERROR;
1423         }
1424
1425         if (0 == this_time) {
1426             if (s->is_chunked) {
1427                 s->no_more_chunks = 1;  /* read no more */
1428             }
1429             break;
1430         }
1431         rdlen += this_time;
1432     }
1433
1434     JK_TRACE_EXIT(l);
1435     return (int)rdlen;
1436 }
1437
1438
1439 /*
1440  * Read data from AJP13/AJP14 protocol
1441  * Returns -1 on error, else number of bytes read
1442  */
1443
1444 static int ajp_read_into_msg_buff(ajp_endpoint_t * ae,
1445                                   jk_ws_service_t *r,
1446                                   jk_msg_buf_t *msg, int len, jk_logger_t *l)
1447 {
1448     unsigned char *read_buf = msg->buf;
1449
1450     JK_TRACE_ENTER(l);
1451
1452     jk_b_reset(msg);
1453
1454     read_buf += AJP_HEADER_LEN; /* leave some space for the buffer headers */
1455     read_buf += AJP_HEADER_SZ_LEN;      /* leave some space for the read length */
1456
1457     /* Pick the max size since we don't know the content_length */
1458     if (r->is_chunked && len == 0) {
1459         len = AJP13_MAX_SEND_BODY_SZ;
1460     }
1461
1462     if ((len = ajp_read_fully_from_server(r, l, read_buf, len)) < 0) {
1463         jk_log(l, JK_LOG_INFO,
1464                "(%s) receiving data from client failed. "
1465                "Connection aborted or network problems",
1466                ae->worker->name);
1467         JK_TRACE_EXIT(l);
1468         return JK_CLIENT_RD_ERROR;
1469     }
1470
1471     if (!r->is_chunked) {
1472         ae->left_bytes_to_send -= len;
1473     }
1474
1475     if (len > 0) {
1476         /* Recipient recognizes empty packet as end of stream, not
1477            an empty body packet */
1478         if (0 != jk_b_append_int(msg, (unsigned short)len)) {
1479             jk_log(l, JK_LOG_INFO,
1480                    "Failed appending message length");
1481             JK_TRACE_EXIT(l);
1482             return JK_CLIENT_RD_ERROR;
1483         }
1484     }
1485
1486     msg->len += len;
1487
1488     JK_TRACE_EXIT(l);
1489     return len;
1490 }
1491
1492
1493 /*
1494  * send request to Tomcat via Ajp13
1495  * - first try to find reuseable socket
1496  * - if no such available, try to connect
1497  * - send request, but send must be seen as asynchronous,
1498  *   since send() call will return noerror about 95% of time
1499  *   Hopefully we'll get more information on next read.
1500  *
1501  * nb: op->request is the original request msg buffer
1502  *     op->reply is the reply msg buffer which could be scratched
1503  *
1504  * Return values of ajp_send_request() function:
1505  * return value        op->recoverable   reason
1506  * JK_FATAL_ERROR      JK_FALSE          ajp_connection_tcp_send_message() returns JK_FATAL_ERROR
1507  *           Endpoint belongs to unknown protocol.
1508  * JK_FATAL_ERROR      JK_TRUE           ajp_connection_tcp_send_message() returns JK_FALSE
1509  *           Sending request or request body in jk_tcp_socket_sendfull() returns with error.
1510  * JK_FATAL_ERROR      JK_TRUE           Could not connect to backend
1511  * JK_CLIENT_RD_ERROR  JK_FALSE          Error during reading parts of POST body from client
1512  * JK_TRUE             JK_TRUE           All other cases (OK)
1513  */
1514 static int ajp_send_request(jk_endpoint_t *e,
1515                             jk_ws_service_t *s,
1516                             jk_logger_t *l,
1517                             ajp_endpoint_t * ae, ajp_operation_t * op)
1518 {
1519     int err_conn = 0;
1520     int err_cping = 0;
1521     int err_send = 0;
1522     int rc;
1523     int postlen;
1524
1525     JK_TRACE_ENTER(l);
1526
1527     ae->last_errno = 0;
1528     /* Up to now, we can recover */
1529     op->recoverable = JK_TRUE;
1530
1531     /* Check if the previous request really ended
1532      */
1533     if (ae->last_op != JK_AJP13_END_RESPONSE &&
1534         ae->last_op != AJP13_CPONG_REPLY) {
1535         jk_log(l, JK_LOG_INFO,
1536                 "(%s) did not receive END_RESPONSE, "
1537                 "closing socket %d",
1538                 ae->worker->name, ae->sd);
1539         ajp_abort_endpoint(ae, JK_TRUE, l);
1540     }
1541     /*
1542      * First try to check open connections...
1543      */
1544     while (IS_VALID_SOCKET(ae->sd)) {
1545         int err = JK_FALSE;
1546         if (jk_is_socket_connected(ae->sd, l) == JK_FALSE) {
1547             ae->last_errno = errno;
1548             jk_log(l, JK_LOG_DEBUG,
1549                    "(%s) failed sending request, "
1550                    "socket %d is not connected any more (errno=%d)",
1551                    ae->worker->name, ae->sd, ae->last_errno);
1552             ajp_abort_endpoint(ae, JK_FALSE, l);
1553             err = JK_TRUE;
1554             err_conn++;
1555         }
1556         if (ae->worker->prepost_timeout > 0 && !err) {
1557             /* handle cping/cpong if prepost_timeout is set
1558              * If the socket is disconnected no need to handle
1559              * the cping/cpong
1560              */
1561             if (ajp_handle_cping_cpong(ae,
1562                         ae->worker->prepost_timeout, l) == JK_FALSE) {
1563                 jk_log(l, JK_LOG_INFO,
1564                        "(%s) failed sending request, "
1565                        "socket %d prepost cping/cpong failure (errno=%d)",
1566                         ae->worker->name, ae->sd, ae->last_errno);
1567                 /* XXX: Is there any reason to try other
1568                  * connections to the node if one of them fails
1569                  * the cping/cpong heartbeat?
1570                  * Tomcat can be either too busy or simply dead, so
1571                  * there is a chance that all other connections would
1572                  * fail as well.
1573                  */
1574                 err = JK_TRUE;
1575                 err_cping++;
1576             }
1577         }
1578
1579         /* We've got a connected socket and the optional
1580          * cping/cpong worked, so let's send the request now.
1581          */
1582         if (err == JK_FALSE) {
1583             rc = ajp_connection_tcp_send_message(ae, op->request, l);
1584             /* If this worked, we can break out of the loop
1585              * and proceed with the request.
1586              */
1587             if (rc == JK_TRUE) {
1588                 ae->last_op = JK_AJP13_FORWARD_REQUEST;
1589                 break;
1590             }
1591             /* Error during sending the request.
1592              */
1593             err_send++;
1594             if (rc == JK_FATAL_ERROR)
1595                 op->recoverable = JK_FALSE;
1596             jk_log(l, JK_LOG_INFO,
1597                    "(%s) failed sending request (%srecoverable) "
1598                    "(errno=%d)",
1599                     ae->worker->name,
1600                     op->recoverable ? "" : "un",
1601                     ae->last_errno);
1602             JK_TRACE_EXIT(l);
1603             return JK_FATAL_ERROR;
1604         }
1605         /* If we got an error or can't send data, then try to steal another pooled
1606          * connection and try again.  If we are not successful, break out of this
1607          * loop and try to open a new connection after the loop.
1608          */
1609         if (ajp_next_connection(ae, l) == JK_FALSE)
1610             break;
1611     }
1612
1613     /*
1614      * If we failed to reuse a connection, try to reconnect.
1615      */
1616     if (!IS_VALID_SOCKET(ae->sd)) {
1617         /* Could not steal any connection from an endpoint - backend is disconnected */
1618         if (err_conn + err_cping + err_send > 0)
1619             jk_log(l, JK_LOG_INFO,
1620                    "(%s) all endpoints are disconnected, "
1621                    "detected by connect check (%d), cping (%d), send (%d)",
1622                    ae->worker->name, err_conn, err_cping, err_send);
1623         else if (JK_IS_DEBUG_LEVEL(l))
1624             jk_log(l, JK_LOG_DEBUG,
1625                    "(%s) all endpoints are disconnected.",
1626                    ae->worker->name);
1627         /* Connect to the backend.
1628          */
1629         if (ajp_connect_to_endpoint(ae, l) != JK_TRUE) {
1630             jk_log(l, JK_LOG_ERROR,
1631                    "(%s) connecting to backend failed. Tomcat is probably not started "
1632                    "or is listening on the wrong port (errno=%d)",
1633                    ae->worker->name, ae->last_errno);
1634             JK_TRACE_EXIT(l);
1635             return JK_FATAL_ERROR;
1636         }
1637         if (ae->worker->connect_timeout <= 0 &&
1638             ae->worker->prepost_timeout > 0) {
1639             /* handle cping/cpong if prepost_timeout is set
1640              * and we didn't already do a connect cping/cpong.
1641              */
1642             if (ajp_handle_cping_cpong(ae,
1643                         ae->worker->prepost_timeout, l) == JK_FALSE) {
1644                 jk_log(l, JK_LOG_INFO,
1645                        "(%s) failed sending request, "
1646                        "socket %d prepost cping/cpong failure (errno=%d)",
1647                         ae->worker->name, ae->sd, ae->last_errno);
1648                 JK_TRACE_EXIT(l);
1649                 return JK_FATAL_ERROR;
1650             }
1651         }
1652
1653         /* We've got a connected socket and the optional
1654          * cping/cpong worked, so let's send the request now.
1655          */
1656         rc = ajp_connection_tcp_send_message(ae, op->request, l);
1657         /* Error during sending the request.
1658          */
1659         if (rc != JK_TRUE) {
1660             if (rc == JK_FATAL_ERROR)
1661                 op->recoverable = JK_FALSE;
1662             jk_log(l, JK_LOG_ERROR,
1663                    "(%s) failed sending request on a fresh connection (%srecoverable), "
1664                    "socket %d (errno=%d)",
1665                     ae->worker->name, op->recoverable ? "" : "un",
1666                     ae->sd, ae->last_errno);
1667             JK_TRACE_EXIT(l);
1668             return JK_FATAL_ERROR;
1669         }
1670         ae->last_op = JK_AJP13_FORWARD_REQUEST;
1671     }
1672     else if (JK_IS_DEBUG_LEVEL(l))
1673         jk_log(l, JK_LOG_DEBUG,
1674                "(%s) Statistics about invalid connections: "
1675                "connect check (%d), cping (%d), send (%d)",
1676                ae->worker->name, err_conn, err_cping, err_send);
1677
1678     /*
1679      * From now on an error means that we have an internal server error
1680      * or Tomcat crashed.
1681      */
1682
1683     if (JK_IS_DEBUG_LEVEL(l))
1684         jk_log(l, JK_LOG_DEBUG,
1685                "(%s) request body to send %" JK_UINT64_T_FMT " - request body to resend %d",
1686                ae->worker->name, ae->left_bytes_to_send,
1687                op->reply->len - AJP_HEADER_LEN);
1688
1689     /*
1690      * POST recovery job is done here and will work when data to
1691      * POST are less than 8k, since it's the maximum size of op-post buffer.
1692      * We send here the first part of data which was sent previously to the
1693      * remote Tomcat
1694      */
1695
1696     /* Did we have something to resend (ie the op-post has been feeded previously */
1697
1698     postlen = op->post->len;
1699     if (postlen > AJP_HEADER_LEN) {
1700         rc = ajp_connection_tcp_send_message(ae, op->post, l);
1701         /* Error during sending the request body.
1702          */
1703         if (rc != JK_TRUE) {
1704             if (rc == JK_FATAL_ERROR)
1705                 op->recoverable = JK_FALSE;
1706             jk_log(l, JK_LOG_ERROR,
1707                    "(%s) failed sending request body of size %d (%srecoverable), "
1708                    "socket %d (errno=%d)",
1709                     ae->worker->name, postlen, op->recoverable ? "" : "un",
1710                     ae->sd, ae->last_errno);
1711             JK_TRACE_EXIT(l);
1712             return JK_FATAL_ERROR;
1713         }
1714         else {
1715             if (JK_IS_DEBUG_LEVEL(l))
1716                 jk_log(l, JK_LOG_DEBUG, "Resent the request body (%d)",
1717                        postlen);
1718         }
1719     }
1720     else if (s->reco_status == RECO_FILLED) {
1721         /* Recovery in LB MODE */
1722         postlen = s->reco_buf->len;
1723
1724         if (postlen > AJP_HEADER_LEN) {
1725             rc = ajp_connection_tcp_send_message(ae, s->reco_buf, l);
1726             /* Error during sending the request body.
1727              */
1728             if (rc != JK_TRUE) {
1729                 if (rc == JK_FATAL_ERROR)
1730                     op->recoverable = JK_FALSE;
1731                 jk_log(l, JK_LOG_ERROR,
1732                        "(%s) failed sending request body of size %d (lb mode) (%srecoverable), "
1733                        "socket %d (errno=%d)",
1734                         ae->worker->name, postlen, op->recoverable ? "" : "un",
1735                         ae->sd, ae->last_errno);
1736                 JK_TRACE_EXIT(l);
1737                 return JK_FATAL_ERROR;
1738             }
1739         }
1740         else {
1741             if (JK_IS_DEBUG_LEVEL(l))
1742                 jk_log(l, JK_LOG_DEBUG,
1743                        "Resent the request body (lb mode) (%d)", postlen);
1744         }
1745     }
1746     else {
1747         /* We never sent any POST data and we check if we have to send at
1748          * least one block of data (max 8k). These data will be kept in reply
1749          * for resend if the remote Tomcat is down, a fact we will learn only
1750          * doing a read (not yet)
1751          */
1752         /* || s->is_chunked - this can't be done here. The original protocol
1753            sends the first chunk of post data ( based on Content-Length ),
1754            and that's what the java side expects.
1755            Sending this data for chunked would break other ajp13 servers.
1756
1757            Note that chunking will continue to work - using the normal read.
1758          */
1759
1760         if (ae->left_bytes_to_send > 0) {
1761             int len = AJP13_MAX_SEND_BODY_SZ;
1762             if (ae->left_bytes_to_send < (jk_uint64_t)AJP13_MAX_SEND_BODY_SZ) {
1763                 len = (int)ae->left_bytes_to_send;
1764             }
1765             if ((len = ajp_read_into_msg_buff(ae, s, op->post, len, l)) <= 0) {
1766                 if (JK_IS_DEBUG_LEVEL(l))
1767                     jk_log(l, JK_LOG_DEBUG,
1768                            "(%s) browser stop sending data, no need to recover",
1769                             ae->worker->name);
1770                 op->recoverable = JK_FALSE;
1771                 /* Send an empty POST message since per AJP protocol
1772                  * spec whenever we have content length the message
1773                  * packet must be followed with initial POST packet.
1774                  * Size zero will be handled as error in container.
1775                  */
1776                 jk_b_reset(op->post);
1777                 jk_b_append_int(op->post, 0);
1778                 ajp_connection_tcp_send_message(ae, op->post, l);
1779                 JK_TRACE_EXIT(l);
1780                 return JK_CLIENT_RD_ERROR;
1781             }
1782
1783             /* If a RECOVERY buffer is available in LB mode, fill it */
1784             if (s->reco_status == RECO_INITED) {
1785                 jk_b_copy(op->post, s->reco_buf);
1786                 s->reco_status = RECO_FILLED;
1787             }
1788             if (JK_IS_DEBUG_LEVEL(l))
1789                 jk_log(l, JK_LOG_DEBUG,
1790                        "(%s) sending %d bytes of request body",
1791                         ae->worker->name, len);
1792
1793             s->content_read = (jk_uint64_t)len;
1794             rc = ajp_connection_tcp_send_message(ae, op->post, l);
1795             /* Error during sending the request body.
1796              */
1797             if (rc != JK_TRUE) {
1798                 if (rc == JK_FATAL_ERROR)
1799                     op->recoverable = JK_FALSE;
1800                 jk_log(l, JK_LOG_ERROR,
1801                        "(%s) failed sending request body of size %d (%srecoverable), "
1802                        "socket %d (errno=%d)",
1803                         ae->worker->name, len, op->recoverable ? "" : "un",
1804                         ae->sd, ae->last_errno);
1805                 JK_TRACE_EXIT(l);
1806                 return JK_FATAL_ERROR;
1807             }
1808         }
1809     }
1810     JK_TRACE_EXIT(l);
1811     return JK_TRUE;
1812 }
1813
1814
1815 /*
1816  * What to do with incoming data (dispatcher)
1817  */
1818
1819 static int ajp_process_callback(jk_msg_buf_t *msg,
1820                                 jk_msg_buf_t *pmsg,
1821                                 ajp_endpoint_t * ae,
1822                                 jk_ws_service_t *r, jk_logger_t *l)
1823 {
1824     int code = (int)jk_b_get_byte(msg);
1825
1826     JK_TRACE_ENTER(l);
1827
1828     switch (code) {
1829     case JK_AJP13_SEND_HEADERS:
1830         {
1831             int rc;
1832             jk_res_data_t res;
1833             if (ae->last_op == JK_AJP13_SEND_HEADERS) {
1834                 /* Do not send anything to the client.
1835                  * Backend already send us the headers.
1836                  */
1837                 if (JK_IS_DEBUG_LEVEL(l)) {
1838                     jk_log(l, JK_LOG_DEBUG,
1839                            "Already received AJP13_SEND HEADERS");
1840                 }
1841                 JK_TRACE_EXIT(l);
1842                 return JK_AJP13_ERROR;
1843             }
1844             if (!ajp_unmarshal_response(msg, &res, ae, l)) {
1845                 jk_log(l, JK_LOG_ERROR,
1846                        "ajp_unmarshal_response failed");
1847                 JK_TRACE_EXIT(l);
1848                 return JK_AJP13_ERROR;
1849             }
1850             r->http_response_status = res.status;
1851             if (r->extension.fail_on_status_size > 0)
1852                 rc = is_http_status_fail(r->extension.fail_on_status_size,
1853                                          r->extension.fail_on_status, res.status);
1854             else
1855                 rc = is_http_status_fail(ae->worker->http_status_fail_num,
1856                                          ae->worker->http_status_fail, res.status);
1857             if (rc > 0) {
1858                 JK_TRACE_EXIT(l);
1859                 return JK_STATUS_FATAL_ERROR;
1860             }
1861             else if (rc < 0) {
1862                 JK_TRACE_EXIT(l);
1863                 return JK_STATUS_ERROR;
1864             }
1865
1866             if (r->extension.use_server_error_pages &&
1867                 r->http_response_status >= r->extension.use_server_error_pages)
1868                 r->response_blocked = JK_TRUE;
1869
1870             /*
1871              * Call even if response is blocked, since it also handles
1872              * forwarding some headers for special http status codes
1873              * even if the server uses an own error page.
1874              * Example: The WWW-Authenticate header in case of
1875              * HTTP_UNAUTHORIZED (401).
1876              */
1877             r->start_response(r, res.status, res.msg,
1878                               (const char *const *)res.header_names,
1879                               (const char *const *)res.header_values,
1880                               res.num_headers);
1881
1882             if (!r->response_blocked) {
1883                 if (r->flush && r->flush_header)
1884                     r->flush(r);
1885             }
1886         }
1887         return JK_AJP13_SEND_HEADERS;
1888
1889     case JK_AJP13_SEND_BODY_CHUNK:
1890         if (ae->last_op == JK_AJP13_FORWARD_REQUEST) {
1891             /* AJP13_SEND_BODY_CHUNK with length 0 is
1892              * explicit flush packet message.
1893              * Ignore those if they are left over from previous responses.
1894              * Reportedly some versions of JBoss suffer from that problem.
1895              */
1896             if (jk_b_get_int(msg) == 0) {
1897                 jk_log(l, JK_LOG_DEBUG,
1898                        "Ignoring flush message received while sending the request");
1899                 return ae->last_op;
1900             }
1901             /* We have just send a request but received something
1902              * that probably originates from buffered response.
1903              */
1904             if (JK_IS_DEBUG_LEVEL(l)) {
1905                 jk_log(l, JK_LOG_DEBUG,
1906                        "Unexpected AJP13_SEND_BODY_CHUNK");
1907             }
1908             JK_TRACE_EXIT(l);
1909             return JK_AJP13_ERROR;
1910         }
1911         if (!r->response_blocked) {
1912             unsigned int len = (unsigned int)jk_b_get_int(msg);
1913             /*
1914              * Do a sanity check on len to prevent write reading beyond buffer
1915              * boundaries and thus revealing possible sensitive memory
1916              * contents to the client.
1917              * len cannot be larger than msg->len - 3 because the ajp message
1918              * contains the magic byte for JK_AJP13_SEND_BODY_CHUNK (1 byte)
1919              * and the length of the chunk (2 bytes). The remaining part of
1920              * the message is the chunk.
1921              */
1922             if (len > (unsigned int)(msg->len - 3)) {
1923                 jk_log(l, JK_LOG_ERROR,
1924                        "Chunk length too large. Length of AJP message is %i,"
1925                        " chunk length is %i.", msg->len, len);
1926                 JK_TRACE_EXIT(l);
1927                 return JK_INTERNAL_ERROR;
1928             }
1929             if (len == 0) {
1930                 /* AJP13_SEND_BODY_CHUNK with length 0 is
1931                  * explicit flush packet message.
1932                  */
1933                 if (r->response_started) {
1934                     if (r->flush) {
1935                         r->flush(r);
1936                     }
1937                 }
1938                 else {
1939                     jk_log(l, JK_LOG_DEBUG,
1940                            "Ignoring flush message received before headers");
1941                 }
1942             }
1943             else {
1944                 if (!r->write(r, msg->buf + msg->pos, len)) {
1945                     jk_log(l, JK_LOG_INFO,
1946                            "Writing to client aborted or client network problems");
1947                     JK_TRACE_EXIT(l);
1948                     return JK_CLIENT_WR_ERROR;
1949                 }
1950                 if (r->flush && r->flush_packets)
1951                     r->flush(r);
1952             }
1953         }
1954         break;
1955
1956     case JK_AJP13_GET_BODY_CHUNK:
1957         {
1958             int len = (int)jk_b_get_int(msg);
1959
1960             if (len < 0) {
1961                 len = 0;
1962             }
1963             if (len > AJP13_MAX_SEND_BODY_SZ) {
1964                 len = AJP13_MAX_SEND_BODY_SZ;
1965             }
1966             if ((jk_uint64_t)len > ae->left_bytes_to_send) {
1967                 len = (int)ae->left_bytes_to_send;
1968             }
1969
1970             /* the right place to add file storage for upload */
1971             if ((len = ajp_read_into_msg_buff(ae, r, pmsg, len, l)) >= 0) {
1972                 r->content_read += (jk_uint64_t)len;
1973                 JK_TRACE_EXIT(l);
1974                 return JK_AJP13_HAS_RESPONSE;
1975             }
1976
1977             jk_log(l, JK_LOG_INFO,
1978                    "Reading from client aborted or client network problems");
1979
1980             JK_TRACE_EXIT(l);
1981             return JK_CLIENT_RD_ERROR;
1982         }
1983         break;
1984
1985     case JK_AJP13_END_RESPONSE:
1986         ae->reuse = (int)jk_b_get_byte(msg);
1987         if (!ae->reuse) {
1988             /*
1989              * AJP13 protocol reuse flag set to false.
1990              * Tomcat will close its side of the connection.
1991              */
1992             jk_log(l, JK_LOG_WARNING, "AJP13 protocol: Reuse is set to false");
1993         }
1994         else if (r->disable_reuse) {
1995             if (JK_IS_DEBUG_LEVEL(l)) {
1996                 jk_log(l, JK_LOG_DEBUG, "AJP13 protocol: Reuse is disabled");
1997             }
1998             ae->reuse = JK_FALSE;
1999         }
2000         else {
2001             /* Reuse in all cases */
2002             if (JK_IS_DEBUG_LEVEL(l)) {
2003                 jk_log(l, JK_LOG_DEBUG, "AJP13 protocol: Reuse is OK");
2004             }
2005             ae->reuse = JK_TRUE;
2006         }
2007         if (!r->response_blocked) {
2008             if (r->done) {
2009                 /* Done with response */
2010                 r->done(r);
2011             }
2012             else if (r->flush && !r->flush_packets) {
2013                 /* Flush after the last write */
2014                 r->flush(r);
2015             }
2016         }
2017         JK_TRACE_EXIT(l);
2018         return JK_AJP13_END_RESPONSE;
2019         break;
2020
2021     default:
2022         jk_log(l, JK_LOG_ERROR,
2023                "Unknown AJP protocol code: %02X", code);
2024         JK_TRACE_EXIT(l);
2025         return JK_AJP13_ERROR;
2026     }
2027
2028     JK_TRACE_EXIT(l);
2029     return JK_AJP13_NO_RESPONSE;
2030 }
2031
2032 /*
2033  * get replies from Tomcat via Ajp13/Ajp14
2034  * ajp13/ajp14 is async but handling read/send this way prevent nice recovery
2035  * In fact if tomcat link is broken during upload (browser -> apache -> tomcat)
2036  * we'll loose data and we'll have to abort the whole request.
2037  *
2038  * Return values of ajp_get_reply() function:
2039  * return value           op->recoverable    reason
2040  * JK_REPLY_TIMEOUT       ?recovery_options  Reply timeout while waiting for response packet
2041  * JK_FALSE               ?recovery_options  Error during ajp_connection_tcp_get_message()
2042  *           Could not read the AJP packet header
2043  * JK_AJP_PROTOCOL_ERROR: ?recovery_options  Error during ajp_connection_tcp_get_message()
2044  *           Failure after reading the AJP packet header
2045  * JK_STATUS_ERROR        mostly JK_TRUE     ajp_process_callback() returns JK_STATUS_ERROR
2046  *           Recoverable, if callback didn't return with a JK_HAS_RESPONSE before.
2047  *           JK_HAS_RESPONSE: parts of the post buffer are consumed.
2048  * JK_STATUS_FATAL_ERROR  mostly JK_TRUE     ajp_process_callback() returns JK_STATUS_FATAL_ERROR
2049  *           Recoverable, if callback didn't return with a JK_HAS_RESPONSE before.
2050  *           JK_HAS_RESPONSE: parts of the post buffer are consumed.
2051  * JK_FATAL_ERROR         ?                  ajp_process_callback() returns JK_AJP13_ERROR
2052  *           JK_AJP13_ERROR: protocol error, or JK_INTERNAL_ERROR: chunk size to large
2053  * JK_CLIENT_RD_ERROR     ?                  ajp_process_callback() returns JK_CLIENT_RD_ERROR
2054  *           JK_CLIENT_RD_ERROR: could not read post from client.
2055  * JK_CLIENT_WR_ERROR     ?                  ajp_process_callback() returns JK_CLIENT_WR_ERROR
2056  *           JK_CLIENT_WR_ERROR: could not write back result to client
2057  * JK_TRUE                ?                  ajp_process_callback() returns JK_AJP13_END_RESPONSE
2058  * JK_FALSE               ?                  Other unhandled cases (unknown return codes)
2059  */
2060 static int ajp_get_reply(jk_endpoint_t *e,
2061                          jk_ws_service_t *s,
2062                          jk_logger_t *l,
2063                          ajp_endpoint_t * p, ajp_operation_t * op)
2064 {
2065     /* Don't get header from tomcat yet */
2066     int headeratclient = JK_FALSE;
2067
2068     JK_TRACE_ENTER(l);
2069
2070     p->last_errno = 0;
2071     /* Start read all reply message */
2072     while (1) {
2073         int rc = 0;
2074         /* Allow to overwrite reply_timeout on a per URL basis via service struct */
2075         int reply_timeout = s->extension.reply_timeout;
2076         if (reply_timeout < 0)
2077             reply_timeout = p->worker->reply_timeout;
2078         /* If we set a reply timeout, check if something is available */
2079         if (reply_timeout > 0) {
2080             if (jk_is_input_event(p->sd, reply_timeout, l) ==
2081                 JK_FALSE) {
2082                 p->last_errno = errno;
2083                 jk_log(l, JK_LOG_ERROR,
2084                        "(%s) Timeout with waiting reply from tomcat. "
2085                        "Tomcat is down, stopped or network problems (errno=%d)",
2086                        p->worker->name, p->last_errno);
2087                 /* We can't trust this connection any more. */
2088                 ajp_abort_endpoint(p, JK_TRUE, l);
2089                 if (headeratclient == JK_FALSE) {
2090                     if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST)
2091                         op->recoverable = JK_FALSE;
2092                     /*
2093                      * We revert back to recoverable, if recovery_opts allow it for GET or HEAD
2094                      */
2095                     if (op->recoverable == JK_FALSE) {
2096                         if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_HEAD) {
2097                             if (!strcmp(s->method, "HEAD"))
2098                                 op->recoverable = JK_TRUE;
2099                         }
2100                         else if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_GET) {
2101                             if (!strcmp(s->method, "GET"))
2102                                 op->recoverable = JK_TRUE;
2103                         }
2104                     }
2105                 }
2106                 else {
2107                     if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER)
2108                         op->recoverable = JK_FALSE;
2109                 }
2110
2111                 JK_TRACE_EXIT(l);
2112                 return JK_REPLY_TIMEOUT;
2113             }
2114         }
2115
2116         if ((rc = ajp_connection_tcp_get_message(p, op->reply, l)) != JK_TRUE) {
2117             if (headeratclient == JK_FALSE) {
2118                 jk_log(l, JK_LOG_ERROR,
2119                        "(%s) Tomcat is down or refused connection. "
2120                        "No response has been sent to the client (yet)",
2121                        p->worker->name);
2122                 /*
2123                  * communication with tomcat has been interrupted BEFORE
2124                  * headers have been sent to the client.
2125                  */
2126
2127                 /*
2128                  * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCGETREQUEST
2129                  */
2130                 if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCGETREQUEST)
2131                     op->recoverable = JK_FALSE;
2132                 /*
2133                  * We revert back to recoverable, if recovery_opts allow it for GET or HEAD
2134                  */
2135                 if (op->recoverable == JK_FALSE) {
2136                     if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_HEAD) {
2137                         if (!strcmp(s->method, "HEAD"))
2138                             op->recoverable = JK_TRUE;
2139                     }
2140                     else if (p->worker->recovery_opts & RECOVER_ALWAYS_HTTP_GET) {
2141                         if (!strcmp(s->method, "GET"))
2142                             op->recoverable = JK_TRUE;
2143                     }
2144                 }
2145
2146             }
2147             else {
2148                 jk_log(l, JK_LOG_ERROR,
2149                        "(%s) Tomcat is down or network problems. "
2150                        "Part of the response has already been sent to the client",
2151                        p->worker->name);
2152
2153                 /* communication with tomcat has been interrupted AFTER
2154                  * headers have been sent to the client.
2155                  * headers (and maybe parts of the body) have already been
2156                  * sent, therefore the response is "complete" in a sense
2157                  * that nobody should append any data, especially no 500 error
2158                  * page of the webserver!
2159                  */
2160
2161                 /*
2162                  * We mark it unrecoverable if recovery_opts set to RECOVER_ABORT_IF_TCSENDHEADER
2163                  */
2164                 if (p->worker->recovery_opts & RECOVER_ABORT_IF_TCSENDHEADER)
2165                     op->recoverable = JK_FALSE;
2166
2167             }
2168
2169             JK_TRACE_EXIT(l);
2170             return rc;
2171         }
2172
2173         rc = ajp_process_callback(op->reply, op->post, p, s, l);
2174         p->last_op = rc;
2175         /* no more data to be sent, fine we have finish here */
2176         if (JK_AJP13_END_RESPONSE == rc) {
2177             JK_TRACE_EXIT(l);
2178             return JK_TRUE;
2179         }
2180         else if (JK_AJP13_SEND_HEADERS == rc) {
2181             if (headeratclient == JK_FALSE)
2182                 headeratclient = JK_TRUE;
2183             else {
2184                 /* Backend send headers twice?
2185                  * This is protocol violation
2186                  */
2187                 jk_log(l, JK_LOG_ERROR,
2188                        "(%s) Tomcat already send headers",
2189                         p->worker->name);
2190                 op->recoverable = JK_FALSE;
2191                 JK_TRACE_EXIT(l);
2192                 return JK_FALSE;
2193             }
2194         }
2195         else if (JK_STATUS_ERROR == rc || JK_STATUS_FATAL_ERROR == rc) {
2196             jk_log(l, JK_LOG_INFO,
2197                    "(%s) request failed%s, "
2198                    "because of response status %d, ",
2199                    p->worker->name,
2200                    rc == JK_STATUS_FATAL_ERROR ? "" : " (soft)",
2201                    s->http_response_status);
2202             JK_TRACE_EXIT(l);
2203             return rc;
2204         }
2205         else if (JK_AJP13_HAS_RESPONSE == rc) {
2206             /*
2207              * in upload-mode there is no second chance since
2208              * we may have already sent part of the uploaded data
2209              * to Tomcat.
2210              * In this case if Tomcat connection is broken we must
2211              * abort request and indicate error.
2212              * A possible work-around could be to store the uploaded
2213              * data to file and replay for it
2214              */
2215             op->recoverable = JK_FALSE;
2216             rc = ajp_connection_tcp_send_message(p, op->post, l);
2217             if (rc < 0) {
2218                 jk_log(l, JK_LOG_ERROR,
2219                        "(%s) Tomcat is down or network problems",
2220                         p->worker->name);
2221                 JK_TRACE_EXIT(l);
2222                 return JK_FALSE;
2223             }
2224         }
2225         else if (JK_AJP13_ERROR == rc) {
2226             /*
2227              * Tomcat has send invalid AJP message.
2228              * Loadbalancer if present will decide if
2229              * failover is possible.
2230              */
2231             JK_TRACE_EXIT(l);
2232             return JK_FATAL_ERROR;
2233         }
2234         else if (JK_CLIENT_RD_ERROR == rc) {
2235             /*
2236              * Client has stop sending to us, so get out.
2237              * We assume this isn't our fault, so just a normal exit.
2238              */
2239             JK_TRACE_EXIT(l);
2240             return JK_CLIENT_RD_ERROR;
2241         }
2242         else if (JK_CLIENT_WR_ERROR == rc) {
2243             /*
2244              * Client has stop receiving to us, so get out.
2245              * We assume this isn't our fault, so just a normal exit.
2246              */
2247             JK_TRACE_EXIT(l);
2248             return JK_CLIENT_WR_ERROR;
2249         }
2250         else if (JK_INTERNAL_ERROR == rc) {
2251             /*
2252              * Internal error, like memory allocation or invalid packet lengths.
2253              */
2254             JK_TRACE_EXIT(l);
2255             return JK_FATAL_ERROR;
2256         }
2257         else if (JK_AJP13_NO_RESPONSE == rc) {
2258             /*
2259              * This is fine, loop again, more data to send.
2260              */
2261             continue;
2262         }
2263         else if (rc < 0) {
2264             op->recoverable = JK_FALSE;
2265             jk_log(l, JK_LOG_ERROR,
2266                    "(%s) Callback returns with unknown value %d",
2267                     p->worker->name, rc);
2268             JK_TRACE_EXIT(l);
2269             return JK_FALSE;
2270         }
2271     }
2272     /* XXX: Not reached? */
2273     JK_TRACE_EXIT(l);
2274     return JK_FALSE;
2275 }
2276
2277 static void ajp_update_stats(jk_endpoint_t *e, ajp_worker_t *aw, int rc, jk_logger_t *l)
2278 {
2279     aw->s->readed += e->rd;
2280     aw->s->transferred += e->wr;
2281     if (aw->s->busy)
2282         aw->s->busy--;
2283     if (rc == JK_TRUE) {
2284         aw->s->state = JK_AJP_STATE_OK;
2285     }
2286     else if (rc == JK_CLIENT_ERROR) {
2287         aw->s->state = JK_AJP_STATE_OK;
2288         aw->s->client_errors++;
2289     }
2290     else {
2291         aw->s->state = JK_AJP_STATE_ERROR;
2292         aw->s->errors++;
2293         aw->s->error_time = time(NULL);
2294     }
2295 }
2296
2297 /*
2298  * service is now splitted in ajp_send_request and ajp_get_reply
2299  * much more easier to do errors recovery
2300  *
2301  * We serve here the request, using AJP13/AJP14 (e->proto)
2302  *
2303  * Return values of service() method for ajp13/ajp14 worker:
2304  * return value      is_error              e->recoverable     reason
2305  * JK_FALSE          JK_HTTP_SERVER_ERROR  TRUE               Invalid Parameters (null values)
2306  * JK_SERVER_ERROR   JK_HTTP_SERVER_ERROR  TRUE               Error during initializing empty request, response or post body objects
2307  * JK_CLIENT_ERROR   JK_HTTP_REQUEST_TOO_LARGE JK_TRUE        Request doesn't fit into buffer (error during ajp_marshal_into_msgb())
2308  * JK_CLIENT_ERROR   JK_HTTP_BAD_REQUEST   JK_FALSE           Error during reading parts of POST body from client
2309  * JK_FATAL_ERROR    JK_HTTP_SERVER_ERROR  JK_FALSE           If ajp_send_request() returns JK_FATAL_ERROR and !op->recoverable.
2310  * JK_FATAL_ERROR    JK_HTTP_SERVER_ERROR  JK_FALSE           If ajp_send_request() returns JK_TRUE but !op->recoverable.
2311  *           This should never happen.
2312  * JK_CLIENT_ERROR   JK_HTTP_BAD_REQUEST   ?                  ajp_get_reply() returns JK_CLIENT_RD_ERROR
2313  * JK_CLIENT_ERROR   JK_HTTP_OK            ?                  ajp_get_reply() returns JK_CLIENT_WR_ERROR
2314  * JK_FATAL_ERROR    JK_HTTP_SERVER_ERROR  JK_TRUE            ajp_get_reply() returns JK_FATAL_ERROR
2315  *           JK_FATAL_ERROR: protocol error or internal error
2316  * JK_FATAL_ERROR    JK_HTTP_SERVER_ERROR  JK_FALSE           ajp_get_reply() returns JK_FATAL_ERROR
2317  *           JK_FATAL_ERROR: protocol error or internal error
2318  * JK_STATUS_ERROR   JK_HTTP_SERVER_BUSY   JK_TRUE            ajp_get_reply() returns JK_STATUS_ERROR
2319  *           Only if op->recoverable and no more ajp13/ajp14 direct retries
2320  * JK_STATUS_ERROR   JK_HTTP_SERVER_BUSY   JK_FALSE           ajp_get_reply() returns JK_STATUS_ERROR
2321  *           Only if !op->recoverable
2322  * JK_STATUS_FATAL_ERROR JK_HTTP_SERVER_BUSY  JK_TRUE         ajp_get_reply() returns JK_STATUS_ERROR
2323  *           Only if op->recoverable and no more ajp13/ajp14 direct retries
2324  * JK_STATUS_FATAL_ERROR JK_HTTP_SERVER_BUSY  JK_FALSE        ajp_get_reply() returns JK_STATUS_FATAL_ERROR
2325  *           Only if !op->recoverable
2326  * JK_REPLY_TIMEOUT  JK_HTTP_GATEWAY_TIME_OUT JK_TRUE         ajp_get_reply() returns JK_REPLY_TIMEOUT
2327  * JK_AJP_PROTOCOL_ERROR JK_HTTP_GATEWAY_TIME_OUT ?           ajp_get_reply() returns JK_AJP_PROTOCOL_ERROR
2328  * ??? JK_FATAL_ERROR    JK_HTTP_GATEWAY_TIME_OUT JK_FALSE    ajp_get_reply() returns something else
2329  *           Only if !op->recoverable
2330  * ??? JK_FALSE      JK_HTTP_SERVER_BUSY   JK_TRUE            ajp_get_reply() returns JK_FALSE
2331  *           Only if op->recoverable and no more ajp13/ajp14 direct retries
2332  * JK_TRUE           JK_HTTP_OK            ?                  OK
2333  */
2334 static int JK_METHOD ajp_service(jk_endpoint_t *e,
2335                                  jk_ws_service_t *s,
2336                                  jk_logger_t *l, int *is_error)
2337 {
2338     int i;
2339     int err = JK_TRUE;
2340     ajp_operation_t oper;
2341     ajp_operation_t *op = &oper;
2342     ajp_endpoint_t *p;
2343     ajp_worker_t *aw;
2344     int log_error;
2345     int rc = JK_UNSET;
2346     char *msg = "";
2347     int retry_interval;
2348
2349     JK_TRACE_ENTER(l);
2350
2351     if (!e || !e->endpoint_private || !s || !is_error) {
2352         JK_LOG_NULL_PARAMS(l);
2353         if (is_error)
2354             *is_error = JK_HTTP_SERVER_ERROR;
2355         JK_TRACE_EXIT(l);
2356         return JK_FALSE;
2357     }
2358
2359     p = e->endpoint_private;
2360     aw = p->worker;
2361
2362     if (aw->sequence != aw->s->h.sequence)
2363         jk_ajp_pull(aw, JK_FALSE, l);
2364
2365     aw->s->used++;
2366
2367     /* Set returned error to SERVER ERROR */
2368     *is_error = JK_HTTP_SERVER_ERROR;
2369
2370     op->request = jk_b_new(&(p->pool));
2371     if (!op->request) {
2372         jk_log(l, JK_LOG_ERROR,
2373                "Failed allocating AJP message");
2374         JK_TRACE_EXIT(l);
2375         return JK_SERVER_ERROR;
2376     }
2377     if (jk_b_set_buffer_size(op->request, aw->max_packet_size)) {
2378         jk_log(l, JK_LOG_ERROR,
2379                "Failed allocating AJP message buffer");
2380         JK_TRACE_EXIT(l);
2381         return JK_SERVER_ERROR;
2382     }
2383     jk_b_reset(op->request);
2384
2385     op->reply = jk_b_new(&(p->pool));
2386     if (!op->reply) {
2387         jk_log(l, JK_LOG_ERROR,
2388                "Failed allocating AJP message");
2389         JK_TRACE_EXIT(l);
2390         return JK_SERVER_ERROR;
2391     }
2392     if (jk_b_set_buffer_size(op->reply, aw->max_packet_size)) {
2393         jk_log(l, JK_LOG_ERROR,
2394                "Failed allocating AJP message buffer");
2395         JK_TRACE_EXIT(l);
2396         return JK_SERVER_ERROR;
2397     }
2398
2399     op->post = jk_b_new(&(p->pool));
2400     if (!op->post) {
2401         jk_log(l, JK_LOG_ERROR,
2402                "Failed allocating AJP message");
2403         JK_TRACE_EXIT(l);
2404         return JK_SERVER_ERROR;
2405     }
2406     if (jk_b_set_buffer_size(op->post, aw->max_packet_size)) {
2407         jk_log(l, JK_LOG_ERROR,
2408                "Failed allocating AJP message buffer");
2409         JK_TRACE_EXIT(l);
2410         return JK_SERVER_ERROR;
2411     }
2412     jk_b_reset(op->post);
2413
2414     /* Set returned error to OK */
2415     *is_error = JK_HTTP_OK;
2416
2417     op->recoverable = JK_TRUE;
2418     op->uploadfd = -1;      /* not yet used, later ;) */
2419
2420     p->left_bytes_to_send = s->content_length;
2421     p->reuse = JK_FALSE;
2422     p->hard_close = JK_FALSE;
2423
2424     s->secret = aw->secret;
2425
2426     /*
2427      * We get here initial request (in op->request)
2428      */
2429     if (!ajp_marshal_into_msgb(op->request, s, l, p)) {
2430         *is_error = JK_HTTP_REQUEST_TOO_LARGE;
2431         jk_log(l, JK_LOG_INFO,
2432                 "Creating AJP message failed, "
2433                 "without recovery");
2434         aw->s->client_errors++;
2435         JK_TRACE_EXIT(l);
2436         return JK_CLIENT_ERROR;
2437     }
2438
2439     if (JK_IS_DEBUG_LEVEL(l)) {
2440         jk_log(l, JK_LOG_DEBUG, "processing %s with %d retries",
2441                aw->name, aw->retries);
2442     }
2443     aw->s->busy++;
2444     if (aw->s->state == JK_AJP_STATE_ERROR)
2445         aw->s->state = JK_AJP_STATE_PROBE;
2446     if (aw->s->busy > aw->s->max_busy)
2447         aw->s->max_busy = aw->s->busy;
2448     retry_interval = p->worker->retry_interval;
2449     for (i = 0; i < aw->retries; i++) {
2450         /* Reset reply message buffer for each retry */
2451         jk_b_reset(op->reply);
2452
2453         /*
2454          * ajp_send_request() already locally handles
2455          * reconnecting and broken connection detection.
2456          * So if we already failed in it, wait a bit before
2457          * retrying the same backend.
2458          */
2459         if (i > 0 && retry_interval >= 0) {
2460             if (JK_IS_DEBUG_LEVEL(l))
2461                 jk_log(l, JK_LOG_DEBUG,
2462                        "retry %d, sleeping for %d ms before retrying",
2463                        i, retry_interval);
2464             jk_sleep(retry_interval);
2465             /* Pull shared memory if something changed during sleep */
2466             if (aw->sequence != aw->s->h.sequence)
2467                 jk_ajp_pull(aw, JK_FALSE, l);
2468         }
2469         /*
2470          * We're using op->request which hold initial request
2471          * if Tomcat is stopped or restarted, we will pass op->request
2472          * to next valid tomcat.
2473          */
2474         log_error = JK_TRUE;
2475         rc = JK_UNSET;
2476         msg = "";
2477         err = ajp_send_request(e, s, l, p, op);
2478         e->recoverable = op->recoverable;
2479         if (err == JK_CLIENT_RD_ERROR) {
2480             *is_error = JK_HTTP_BAD_REQUEST;
2481             msg = "because of client read error";
2482             aw->s->client_errors++;
2483             rc = JK_CLIENT_ERROR;
2484             log_error = JK_FALSE;
2485             e->recoverable = JK_FALSE;
2486             /* Ajp message set reuse to TRUE in END_REQUEST message
2487              * However due to client bad request if the recovery
2488              * RECOVER_ABORT_IF_CLIENTERROR is set the physical connection
2489              * will be closed and application in Tomcat can catch that
2490              * generated exception, knowing the client aborted the
2491              * connection. This AJP protocol limitation, where we
2492              * should actually send some packet informing the backend
2493              * that client broke the connection in a middle of
2494              * request/response cycle.
2495              */
2496             if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) {
2497                 /* Mark the endpoint for shutdown */
2498                 p->reuse = JK_FALSE;
2499                 p->hard_close = JK_TRUE;
2500             }
2501         }
2502         else if (err == JK_FATAL_ERROR) {
2503             *is_error = JK_HTTP_SERVER_BUSY;
2504             msg = "because of error during request sending";
2505             rc = err;
2506             if (!op->recoverable) {
2507                 *is_error = JK_HTTP_SERVER_ERROR;
2508                 msg = "because of protocol error during request sending";
2509             }
2510         }
2511         else if (err == JK_TRUE && op->recoverable) {
2512             /* Up to there we can recover */
2513
2514             err = ajp_get_reply(e, s, l, p, op);
2515             e->recoverable = op->recoverable;
2516             if (err == JK_TRUE) {
2517                 *is_error = JK_HTTP_OK;
2518                 /* Done with the request */
2519                 ajp_update_stats(e, aw, JK_TRUE, l);
2520                 JK_TRACE_EXIT(l);
2521                 return JK_TRUE;
2522             }
2523
2524             if (err == JK_CLIENT_RD_ERROR) {
2525                 *is_error = JK_HTTP_BAD_REQUEST;
2526                 msg = "because of client read error";
2527                 aw->s->client_errors++;
2528                 rc = JK_CLIENT_ERROR;
2529                 log_error = JK_FALSE;
2530                 e->recoverable = JK_FALSE;
2531                 op->recoverable = JK_FALSE;
2532                 if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) {
2533                     /* Mark the endpoint for shutdown */
2534                     p->reuse = JK_FALSE;
2535                     p->hard_close = JK_TRUE;
2536                 }
2537             }
2538             else if (err == JK_CLIENT_WR_ERROR) {
2539                 /* XXX: Is this correct to log this as 200? */
2540                 *is_error = JK_HTTP_OK;
2541                 msg = "because of client write error";
2542                 aw->s->client_errors++;
2543                 rc = JK_CLIENT_ERROR;
2544                 log_error = JK_FALSE;
2545                 e->recoverable = JK_FALSE;
2546                 op->recoverable = JK_FALSE;
2547                 if (aw->recovery_opts & RECOVER_ABORT_IF_CLIENTERROR) {
2548                     /* Mark the endpoint for shutdown */
2549                     p->reuse = JK_FALSE;
2550                     p->hard_close = JK_TRUE;
2551                 }
2552             }
2553             else if (err == JK_FATAL_ERROR) {
2554                 *is_error = JK_HTTP_SERVER_ERROR;
2555                 msg = "because of server error";
2556                 rc = err;
2557             }
2558             else if (err == JK_REPLY_TIMEOUT) {
2559                 *is_error = JK_HTTP_GATEWAY_TIME_OUT;
2560                 msg = "because of reply timeout";
2561                 aw->s->reply_timeouts++;
2562                 rc = err;
2563             }
2564             else if (err == JK_STATUS_ERROR || err == JK_STATUS_FATAL_ERROR) {
2565                 *is_error = JK_HTTP_SERVER_BUSY;
2566                 msg = "because of response status";
2567                 rc = err;
2568             }
2569             else if (err == JK_AJP_PROTOCOL_ERROR) {
2570                 *is_error = JK_HTTP_BAD_GATEWAY;
2571                 msg = "because of protocol error";
2572                 rc = err;
2573             }
2574             /* This should only be the cases err == JK_FALSE */
2575             else {
2576                 /* if we can't get reply, check if unrecoverable flag was set
2577                  * if is_recoverable_error is cleared, we have started
2578                  * receiving upload data and we must consider that
2579                  * operation is no more recoverable
2580                  */
2581                 *is_error = JK_HTTP_BAD_GATEWAY;
2582                 msg = "";
2583                 rc = JK_FALSE;
2584             }
2585         }
2586         else {
2587             /* XXX: this should never happen:
2588              *      ajp_send_request() never returns JK_TRUE if !op->recoverable.
2589              *      and all other return values have already been handled.
2590              */
2591             e->recoverable = JK_FALSE;
2592             *is_error = JK_HTTP_SERVER_ERROR;
2593             msg = "because of an unknown reason";
2594             rc = JK_FATAL_ERROR;
2595             jk_log(l, JK_LOG_ERROR,
2596                    "(%s) unexpected condition err=%d recoverable=%d",
2597                    aw->name, err, op->recoverable);
2598         }
2599         if (!op->recoverable && log_error == JK_TRUE) {
2600             jk_log(l, JK_LOG_ERROR,
2601                    "(%s) sending request to tomcat failed (unrecoverable), "
2602                    "%s "
2603                    "(attempt=%d)",
2604                    aw->name, msg, i + 1);
2605         }
2606         else {
2607             jk_log(l, JK_LOG_INFO,
2608                    "(%s) sending request to tomcat failed (%srecoverable), "
2609                    "%s "
2610                    "(attempt=%d)",
2611                    aw->name,
2612                    op->recoverable ? "" : "un",
2613                    msg, i + 1);
2614         }
2615         if (!op->recoverable) {
2616             ajp_update_stats(e, aw, rc, l);
2617             JK_TRACE_EXIT(l);
2618             return rc;
2619         }
2620         /* Get another connection from the pool and try again.
2621          * Note: All sockets are probably closed already.
2622          */
2623         ajp_next_connection(p, l);
2624     }
2625     /* Log the error only once per failed request. */
2626     jk_log(l, JK_LOG_ERROR,
2627            "(%s) connecting to tomcat failed.",
2628            aw->name);
2629
2630     ajp_update_stats(e, aw, rc, l);
2631     JK_TRACE_EXIT(l);
2632     return rc;
2633 }
2634
2635 /*
2636  * Validate the worker (ajp13/ajp14)
2637  */
2638
2639 int ajp_validate(jk_worker_t *pThis,
2640                  jk_map_t *props,
2641                  jk_worker_env_t *we, jk_logger_t *l, int proto)
2642 {
2643     int port;
2644     const char *host;
2645
2646     JK_TRACE_ENTER(l);
2647
2648     if (proto == AJP13_PROTO) {
2649         port = AJP13_DEF_PORT;
2650         host = AJP13_DEF_HOST;
2651     }
2652     else if (proto == AJP14_PROTO) {
2653         port = AJP14_DEF_PORT;
2654         host = AJP14_DEF_HOST;
2655     }
2656     else {
2657         jk_log(l, JK_LOG_ERROR,
2658                "unknown protocol %d", proto);
2659         JK_TRACE_EXIT(l);
2660         return JK_FALSE;
2661     }
2662
2663     if (pThis && pThis->worker_private) {
2664         ajp_worker_t *p = pThis->worker_private;
2665         p->port = jk_get_worker_port(props, p->name, port);
2666         if (!host) {
2667             host = "undefined";
2668         }
2669         strncpy(p->host, jk_get_worker_host(props, p->name, host), JK_SHM_STR_SIZ);
2670
2671         if (JK_IS_DEBUG_LEVEL(l))
2672             jk_log(l, JK_LOG_DEBUG,
2673                    "worker %s contact is '%s:%d'",
2674                    p->name, p->host, p->port);
2675         /* Copy the contact to shm */
2676         strncpy(p->s->host, p->host, JK_SHM_STR_SIZ);
2677         p->s->port = p->port;
2678         p->s->addr_sequence = p->addr_sequence = 0;
2679         /* Resolve if port > 0.
2680          */
2681         if (p->port > 0) {
2682             if (jk_resolve(p->host, p->port, &p->worker_inet_addr, we->pool, l)) {
2683                 JK_TRACE_EXIT(l);
2684                 return JK_TRUE;
2685             }
2686             jk_log(l, JK_LOG_ERROR,
2687                    "worker %s can't resolve tomcat address %s",
2688                    p->name, p->host);
2689             p->s->port = p->port = 0;
2690             if (JK_IS_DEBUG_LEVEL(l))
2691                 jk_log(l, JK_LOG_DEBUG,
2692                        "worker %s contact is disabled",
2693                        p->name);
2694             JK_TRACE_EXIT(l);
2695             return JK_TRUE;
2696         }
2697         else {
2698             p->s->port = p->port = 0;
2699             if (JK_IS_DEBUG_LEVEL(l))
2700                 jk_log(l, JK_LOG_DEBUG,
2701                        "worker %s contact is disabled",
2702                        p->name);
2703             JK_TRACE_EXIT(l);
2704             return JK_TRUE;
2705         }
2706     }
2707     else {
2708         JK_LOG_NULL_PARAMS(l);
2709     }
2710
2711     JK_TRACE_EXIT(l);
2712     return JK_FALSE;
2713 }
2714
2715 static int ajp_create_endpoint_cache(ajp_worker_t *p, int proto, jk_logger_t *l)
2716 {
2717     unsigned int i;
2718     time_t now = time(NULL);
2719
2720     JK_TRACE_ENTER(l);
2721
2722     p->ep_cache = (ajp_endpoint_t **)calloc(1, sizeof(ajp_endpoint_t *) *
2723                                             p->ep_cache_sz);
2724     if (!p->ep_cache) {
2725         JK_TRACE_EXIT(l);
2726         return JK_FALSE;
2727     }
2728     if (JK_IS_DEBUG_LEVEL(l))
2729         jk_log(l, JK_LOG_DEBUG,
2730                 "setting connection pool size to %u with min %u and acquire timeout %d",
2731                 p->ep_cache_sz, p->ep_mincache_sz, p->cache_acquire_timeout);
2732     for (i = 0; i < p->ep_cache_sz; i++) {
2733         p->ep_cache[i] = (ajp_endpoint_t *)calloc(1, sizeof(ajp_endpoint_t));
2734         if (!p->ep_cache[i]) {
2735             jk_log(l, JK_LOG_ERROR,
2736                     "allocating endpoint slot %d (errno=%d)",
2737                     i, errno);
2738             JK_TRACE_EXIT(l);
2739             return JK_FALSE;
2740         }
2741         p->ep_cache[i]->sd = JK_INVALID_SOCKET;
2742         p->ep_cache[i]->reuse = JK_FALSE;
2743         p->ep_cache[i]->hard_close = JK_FALSE;
2744         p->ep_cache[i]->last_access = now;
2745         jk_open_pool(&(p->ep_cache[i]->pool), p->ep_cache[i]->buf,
2746                      sizeof(p->ep_cache[i]->buf));
2747         p->ep_cache[i]->worker = p;
2748         p->ep_cache[i]->endpoint.endpoint_private = p->ep_cache[i];
2749         p->ep_cache[i]->proto = proto;
2750         p->ep_cache[i]->endpoint.service = ajp_service;
2751         p->ep_cache[i]->endpoint.done    = ajp_done;
2752         p->ep_cache[i]->last_op = JK_AJP13_END_RESPONSE;
2753         p->ep_cache[i]->addr_sequence = 0;
2754     }
2755
2756     JK_TRACE_EXIT(l);
2757     return JK_TRUE;
2758 }
2759
2760 int ajp_init(jk_worker_t *pThis,
2761              jk_map_t *props, jk_worker_env_t *we, jk_logger_t *l, int proto)
2762 {
2763     int rc = JK_FALSE;
2764     int cache;
2765     /*
2766      * start the connection cache
2767      */
2768     JK_TRACE_ENTER(l);
2769
2770     cache = jk_get_worker_def_cache_size(proto);
2771
2772     if (pThis && pThis->worker_private) {
2773         ajp_worker_t *p = pThis->worker_private;
2774         p->worker.we = we;
2775         p->ep_cache_sz = jk_get_worker_cache_size(props, p->name, cache);
2776         p->ep_mincache_sz = jk_get_worker_cache_size_min(props, p->name,
2777                                                          (p->ep_cache_sz+1) / 2);
2778         p->socket_timeout =
2779             jk_get_worker_socket_timeout(props, p->name, AJP_DEF_SOCKET_TIMEOUT);
2780
2781         p->socket_connect_timeout =
2782             jk_get_worker_socket_connect_timeout(props, p->name,
2783                                                  p->socket_timeout * 1000);
2784
2785         p->keepalive =
2786             jk_get_worker_socket_keepalive(props, p->name, JK_FALSE);
2787
2788         p->cache_timeout =
2789             jk_get_worker_cache_timeout(props, p->name,
2790                                         AJP_DEF_CACHE_TIMEOUT);
2791
2792         p->ping_timeout =
2793             jk_get_worker_ping_timeout(props, p->name,
2794                                        AJP_DEF_PING_TIMEOUT);
2795         p->ping_mode =
2796             jk_get_worker_ping_mode(props, p->name,
2797                                     AJP_CPING_NONE);
2798
2799         p->connect_timeout =
2800             jk_get_worker_connect_timeout(props, p->name,
2801                                           AJP_DEF_CONNECT_TIMEOUT);
2802
2803         p->prepost_timeout =
2804             jk_get_worker_prepost_timeout(props, p->name,
2805                                           AJP_DEF_PREPOST_TIMEOUT);
2806
2807         if ((p->ping_mode & AJP_CPING_CONNECT) &&
2808              p->connect_timeout == AJP_DEF_CONNECT_TIMEOUT)
2809             p->connect_timeout = p->ping_timeout;
2810
2811         if ((p->ping_mode & AJP_CPING_PREPOST) &&
2812              p->prepost_timeout == AJP_DEF_PREPOST_TIMEOUT)
2813             p->prepost_timeout = p->ping_timeout;
2814
2815         p->conn_ping_interval =
2816             jk_get_worker_conn_ping_interval(props, p->name, 0);
2817         if ((p->ping_mode & AJP_CPING_INTERVAL) &&
2818             p->conn_ping_interval == 0) {
2819             /* XXX: Ping timeout is in miliseconds
2820              * and ping_interval is in seconds.
2821              * Use 10 times larger value for ping interval
2822              * (ping_timeout / 1000) * 10
2823              */
2824             p->conn_ping_interval = p->ping_timeout / 100;
2825         }
2826         p->reply_timeout =
2827             jk_get_worker_reply_timeout(props, p->name,
2828                                         AJP_DEF_REPLY_TIMEOUT);
2829
2830         p->recovery_opts =
2831             jk_get_worker_recovery_opts(props, p->name,
2832                                         AJP_DEF_RECOVERY_OPTS);
2833
2834         p->retries =
2835             jk_get_worker_retries(props, p->name,
2836                                   JK_RETRIES);
2837
2838         p->max_packet_size =
2839             jk_get_max_packet_size(props, p->name);
2840
2841         p->socket_buf =
2842             jk_get_worker_socket_buffer(props, p->name, p->max_packet_size);
2843
2844         p->retry_interval =
2845             jk_get_worker_retry_interval(props, p->name,
2846                                          JK_SLEEP_DEF);
2847         p->cache_acquire_timeout = jk_get_worker_cache_acquire_timeout(props,
2848                                      p->name, p->retries * p->retry_interval);
2849         p->http_status_fail_num = jk_get_worker_fail_on_status(props, p->name,
2850                                      &p->http_status_fail[0],
2851                                      JK_MAX_HTTP_STATUS_FAILS);
2852
2853         if (p->retries < 1) {
2854             jk_log(l, JK_LOG_INFO,
2855                    "number of retries must be greater then 1. Setting to default=%d",
2856                    JK_RETRIES);
2857             p->retries = JK_RETRIES;
2858         }
2859
2860         p->maintain_time = jk_get_worker_maintain_time(props);
2861         if(p->maintain_time < 0)
2862             p->maintain_time = 0;
2863         p->s->last_maintain_time = time(NULL);
2864         p->s->last_reset = p->s->last_maintain_time;
2865
2866         if (JK_IS_DEBUG_LEVEL(l)) {
2867
2868             jk_log(l, JK_LOG_DEBUG,
2869                    "setting endpoint options:",
2870                    p->keepalive);
2871             jk_log(l, JK_LOG_DEBUG,
2872                    "keepalive:              %d",
2873                    p->keepalive);
2874
2875             jk_log(l, JK_LOG_DEBUG,
2876                    "socket timeout:         %d",
2877                    p->socket_timeout);
2878
2879             jk_log(l, JK_LOG_DEBUG,
2880                    "socket connect timeout: %d",
2881                    p->socket_connect_timeout);
2882
2883             jk_log(l, JK_LOG_DEBUG,
2884                    "buffer size:            %d",
2885                    p->socket_buf);
2886
2887             jk_log(l, JK_LOG_DEBUG,
2888                    "pool timeout:           %d",
2889                    p->cache_timeout);
2890
2891             jk_log(l, JK_LOG_DEBUG,
2892                    "ping timeout:           %d",
2893                    p->ping_timeout);
2894
2895             jk_log(l, JK_LOG_DEBUG,
2896                    "connect timeout:        %d",
2897                    p->connect_timeout);
2898
2899             jk_log(l, JK_LOG_DEBUG,
2900                    "reply timeout:          %d",
2901                    p->reply_timeout);
2902
2903             jk_log(l, JK_LOG_DEBUG,
2904                    "prepost timeout:        %d",
2905                    p->prepost_timeout);
2906
2907             jk_log(l, JK_LOG_DEBUG,
2908                    "recovery options:       %d",
2909                    p->recovery_opts);
2910
2911             jk_log(l, JK_LOG_DEBUG,
2912                    "retries:                %d",
2913                     p->retries);
2914
2915             jk_log(l, JK_LOG_DEBUG,
2916                    "max packet size:        %d",
2917                     p->max_packet_size);
2918
2919             jk_log(l, JK_LOG_DEBUG,
2920                    "retry interval:         %d",
2921                     p->retry_interval);
2922         }
2923         /*
2924          *  Need to initialize secret here since we could return from inside
2925          *  of the following loop
2926          */
2927
2928         p->secret = jk_get_worker_secret(props, p->name);
2929         /* Initialize cache slots */
2930         JK_INIT_CS(&(p->cs), rc);
2931         if (!rc) {
2932             jk_log(l, JK_LOG_ERROR,
2933                    "creating thread lock (errno=%d)",
2934                    errno);
2935             JK_TRACE_EXIT(l);
2936             return JK_FALSE;
2937         }
2938         if (!ajp_create_endpoint_cache(p, proto, l)) {
2939             jk_log(l, JK_LOG_ERROR,
2940                    "allocating connection pool of size %u",
2941                    p->ep_cache_sz);
2942             JK_TRACE_EXIT(l);
2943             return JK_FALSE;
2944         }
2945         rc = JK_TRUE;
2946     }
2947     else {
2948         JK_LOG_NULL_PARAMS(l);
2949     }
2950
2951     JK_TRACE_EXIT(l);
2952     return rc;
2953 }
2954
2955 int JK_METHOD ajp_worker_factory(jk_worker_t **w,
2956                                  const char *name, jk_logger_t *l)
2957 {
2958     ajp_worker_t *aw;
2959
2960     JK_TRACE_ENTER(l);
2961     if (name == NULL || w == NULL) {
2962         JK_LOG_NULL_PARAMS(l);
2963         JK_TRACE_EXIT(l);
2964         return JK_FALSE;
2965     }
2966
2967     aw = (ajp_worker_t *) calloc(1, sizeof(ajp_worker_t));
2968     if (!aw) {
2969         jk_log(l, JK_LOG_ERROR,
2970                "malloc of private_data failed");
2971         JK_TRACE_EXIT(l);
2972         return JK_FALSE;
2973     }
2974
2975     jk_open_pool(&aw->p,
2976                  aw->buf,
2977                  sizeof(jk_pool_atom_t) * TINY_POOL_SIZE);
2978
2979     strncpy(aw->name, name, JK_SHM_STR_SIZ);
2980     aw->login = NULL;
2981
2982     aw->ep_cache_sz = 0;
2983     aw->ep_cache = NULL;
2984     aw->connect_retry_attempts = AJP_DEF_RETRY_ATTEMPTS;
2985     aw->worker.worker_private = aw;
2986
2987     aw->worker.maintain = ajp_maintain;
2988
2989     aw->logon = NULL;
2990
2991     *w = &aw->worker;
2992
2993     aw->s = jk_shm_alloc_ajp_worker(&aw->p);
2994     if (!aw->s) {
2995         jk_close_pool(&aw->p);
2996         free(aw);
2997         jk_log(l, JK_LOG_ERROR,
2998                "allocating ajp worker record from shared memory");
2999         JK_TRACE_EXIT(l);
3000         return JK_FALSE;
3001     }
3002     JK_TRACE_EXIT(l);
3003     return JK_TRUE;
3004 }
3005
3006 int ajp_destroy(jk_worker_t **pThis, jk_logger_t *l, int proto)
3007 {
3008     JK_TRACE_ENTER(l);
3009
3010     if (pThis && *pThis && (*pThis)->worker_private) {
3011         unsigned int i;
3012         ajp_worker_t *aw = (*pThis)->worker_private;
3013
3014         if (JK_IS_DEBUG_LEVEL(l))
3015             jk_log(l, JK_LOG_DEBUG,
3016                    "up to %u endpoints to close",
3017                    aw->ep_cache_sz);
3018
3019         for (i = 0; i < aw->ep_cache_sz; i++) {
3020             if (aw->ep_cache[i])
3021                 ajp_close_endpoint(aw->ep_cache[i], l);
3022         }
3023         free(aw->ep_cache);
3024         JK_DELETE_CS(&(aw->cs), i);
3025
3026         if (aw->login) {
3027              /* take care of removing previously allocated data */
3028             if (aw->login->servlet_engine_name)
3029                 free(aw->login->servlet_engine_name);
3030
3031             free(aw->login);
3032             aw->login = NULL;
3033         }
3034
3035         jk_close_pool(&aw->p);
3036         free(aw);
3037         JK_TRACE_EXIT(l);
3038         return JK_TRUE;
3039     }
3040
3041     JK_LOG_NULL_PARAMS(l);
3042     JK_TRACE_EXIT(l);
3043     return JK_FALSE;
3044 }
3045
3046 int JK_METHOD ajp_done(jk_endpoint_t **e, jk_logger_t *l)
3047 {
3048     JK_TRACE_ENTER(l);
3049
3050     if (e && *e && (*e)->endpoint_private) {
3051         ajp_endpoint_t *p = (*e)->endpoint_private;
3052         int rc;
3053         ajp_worker_t *w = p->worker;
3054
3055         /* set last_access only if needed */
3056         if (w->cache_timeout > 0)
3057             p->last_access = time(NULL);
3058         if (w->s->addr_sequence != p->addr_sequence) {
3059             p->reuse = JK_FALSE;
3060             p->addr_sequence = w->s->addr_sequence;
3061         }
3062         ajp_reset_endpoint(p, l);
3063         *e = NULL;
3064         JK_ENTER_CS(&w->cs, rc);
3065         if (rc) {
3066             int i;
3067
3068             for (i = w->ep_cache_sz - 1; i >= 0; i--) {
3069                 if (w->ep_cache[i] == NULL) {
3070                     w->ep_cache[i] = p;
3071                     break;
3072                 }
3073             }
3074             JK_LEAVE_CS(&w->cs, rc);
3075
3076             if (i >= 0) {
3077                 if (JK_IS_DEBUG_LEVEL(l))
3078                     jk_log(l, JK_LOG_DEBUG,
3079                             "recycling connection pool slot=%u for worker %s",
3080                             i, p->worker->name);
3081                 JK_TRACE_EXIT(l);
3082                 return JK_TRUE;
3083             }
3084             /* This should never hapen because
3085              * there is always free empty cache slot
3086              */
3087             jk_log(l, JK_LOG_ERROR,
3088                     "could not find empty connection pool slot from %u for worker %s",
3089                     w->ep_cache_sz, w->name);
3090             JK_TRACE_EXIT(l);
3091             return JK_FALSE;
3092         }
3093
3094         jk_log(l, JK_LOG_ERROR,
3095                "locking thread (errno=%d)", errno);
3096         JK_TRACE_EXIT(l);
3097         return JK_FALSE;
3098     }
3099
3100     JK_LOG_NULL_PARAMS(l);
3101     JK_TRACE_EXIT(l);
3102     return JK_FALSE;
3103 }
3104
3105 int ajp_get_endpoint(jk_worker_t *pThis,
3106                      jk_endpoint_t **je, jk_logger_t *l, int proto)
3107 {
3108     JK_TRACE_ENTER(l);
3109
3110     if (pThis && pThis->worker_private && je) {
3111         ajp_worker_t *aw = pThis->worker_private;
3112         ajp_endpoint_t *ae = NULL;
3113         int rc;
3114         int retry = 0;
3115
3116         *je = NULL;
3117         /* Loop until cache_acquire_timeout interval elapses */
3118         while ((retry * JK_SLEEP_DEF) < aw->cache_acquire_timeout) {
3119
3120             JK_ENTER_CS(&aw->cs, rc);
3121             if (rc) {
3122                 unsigned int slot;
3123                 /* Try to find connected socket cache entry */
3124                 for (slot = 0; slot < aw->ep_cache_sz; slot++) {
3125                     if (aw->ep_cache[slot] &&
3126                         IS_VALID_SOCKET(aw->ep_cache[slot]->sd)) {
3127                         ae = aw->ep_cache[slot];
3128                         if (ae->reuse) {
3129                             aw->ep_cache[slot] = NULL;
3130                             break;
3131                         }
3132                         else {
3133                             /* XXX: We shouldn't have non reusable
3134                              * opened socket in the cache
3135                              */
3136                             ajp_reset_endpoint(ae, l);
3137                             ae = NULL;
3138                             jk_log(l, JK_LOG_WARNING,
3139                                    "closing non reusable pool slot=%d", slot);
3140                         }
3141                     }
3142                 }
3143                 if (!ae) {
3144                     /* No connected cache entry found.
3145                      * Use the first free one.
3146                      */
3147                     for (slot = 0; slot < aw->ep_cache_sz; slot++) {
3148                         if (aw->ep_cache[slot]) {
3149                             ae = aw->ep_cache[slot];
3150                             aw->ep_cache[slot] = NULL;
3151                             break;
3152                         }
3153                     }
3154                 }
3155                 JK_LEAVE_CS(&aw->cs, rc);
3156                 if (ae) {
3157                     if (aw->cache_timeout > 0)
3158                         ae->last_access = time(NULL);
3159                     *je = &ae->endpoint;
3160                     if (JK_IS_DEBUG_LEVEL(l))
3161                         jk_log(l, JK_LOG_DEBUG,
3162                                "acquired connection pool slot=%u after %d retries",
3163                                slot, retry);
3164                     JK_TRACE_EXIT(l);
3165                     return JK_TRUE;
3166                 }
3167                 else {
3168                     retry++;
3169                     if (JK_IS_DEBUG_LEVEL(l))
3170                         jk_log(l, JK_LOG_DEBUG,
3171                                "could not get free endpoint for worker %s"
3172                                " (retry %d, sleeping for %d ms)",
3173                                aw->name, retry, JK_SLEEP_DEF);
3174                     jk_sleep(JK_SLEEP_DEF);
3175                 }
3176             }
3177             else {
3178                jk_log(l, JK_LOG_ERROR,
3179                       "locking thread (errno=%d)", errno);
3180                 JK_TRACE_EXIT(l);
3181                 return JK_FALSE;
3182
3183             }
3184         }
3185         jk_log(l, JK_LOG_WARNING,
3186                 "Unable to get the free endpoint for worker %s from %u slots",
3187                 aw->name, aw->ep_cache_sz);
3188     }
3189     else {
3190         JK_LOG_NULL_PARAMS(l);
3191     }
3192
3193     JK_TRACE_EXIT(l);
3194     return JK_FALSE;
3195 }
3196
3197 int JK_METHOD ajp_maintain(jk_worker_t *pThis, time_t mstarted, jk_logger_t *l)
3198 {
3199     JK_TRACE_ENTER(l);
3200
3201     if (pThis && pThis->worker_private) {
3202         ajp_worker_t *aw = pThis->worker_private;
3203         time_t now = mstarted;
3204         int rc;
3205         long delta;
3206
3207         jk_shm_lock();
3208
3209         /* Now we check for global maintenance (once for all processes).
3210          * Checking workers for idleness.
3211          * Therefore we globally sync and we use a global timestamp.
3212          * Since it's possible that we come here a few milliseconds
3213          * before the interval has passed, we allow a little tolerance.
3214          */
3215         delta = (long)difftime(mstarted, aw->s->last_maintain_time) + JK_AJP_MAINTAIN_TOLERANCE;
3216         if (delta >= aw->maintain_time) {
3217             aw->s->last_maintain_time = mstarted;
3218             if (aw->s->state == JK_AJP_STATE_OK &&
3219                 aw->s->used == aw->s->used_snapshot)
3220                 aw->s->state = JK_AJP_STATE_IDLE;
3221             aw->s->used_snapshot = aw->s->used;
3222         }
3223
3224         jk_shm_unlock();
3225
3226         /* Do connection pool maintenance only if timeouts or keepalives are set */
3227         if (aw->cache_timeout <= 0 &&
3228             aw->conn_ping_interval <= 0) {
3229             /* Nothing to do. */
3230             JK_TRACE_EXIT(l);
3231             return JK_TRUE;
3232         }
3233
3234         JK_ENTER_CS(&aw->cs, rc);
3235         if (rc) {
3236             unsigned int n = 0, k = 0, cnt = 0;
3237             int i;
3238             unsigned int m, m_count = 0;
3239             jk_sock_t   *m_sock;
3240             /* Count open slots */
3241             for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) {
3242                 if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd))
3243                     cnt++;
3244             }
3245             m_sock = (jk_sock_t *)malloc((cnt + 1) * sizeof(jk_sock_t));
3246             /* Handle worker cache timeouts */
3247             if (aw->cache_timeout > 0) {
3248                 for (i = (int)aw->ep_cache_sz - 1;
3249                      i >= 0; i--) {
3250                     /* Skip the closed sockets */
3251                     if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) {
3252                         int elapsed = (int)difftime(mstarted, aw->ep_cache[i]->last_access);
3253                         if (elapsed > aw->cache_timeout) {
3254                             time_t rt = 0;
3255                             n++;
3256                             if (JK_IS_DEBUG_LEVEL(l))
3257                                 rt = time(NULL);
3258                             aw->ep_cache[i]->reuse = JK_FALSE;
3259                             m_sock[m_count++] = aw->ep_cache[i]->sd;
3260                             aw->ep_cache[i]->sd = JK_INVALID_SOCKET;
3261                             ajp_reset_endpoint(aw->ep_cache[i], l);
3262                             if (JK_IS_DEBUG_LEVEL(l))
3263                                 jk_log(l, JK_LOG_DEBUG,
3264                                         "cleaning pool slot=%d elapsed %d in %d",
3265                                         i, elapsed, (int)(difftime(time(NULL), rt)));
3266                         }
3267                     }
3268                     if (cnt <= aw->ep_mincache_sz + n) {
3269                         if (JK_IS_DEBUG_LEVEL(l)) {
3270                             jk_log(l, JK_LOG_DEBUG,
3271                             "reached pool min size %u from %u cache slots",
3272                             aw->ep_mincache_sz, aw->ep_cache_sz);
3273                         }
3274                         break;
3275                     }
3276                 }
3277             }
3278             /* Handle worker connection keepalive */
3279             if (aw->conn_ping_interval > 0 && aw->ping_timeout > 0) {
3280                 for (i = (int)aw->ep_cache_sz - 1; i >= 0; i--) {
3281                     /* Skip the closed sockets */
3282                     if (aw->ep_cache[i] && IS_VALID_SOCKET(aw->ep_cache[i]->sd)) {
3283                         int elapsed = (int)difftime(now, aw->ep_cache[i]->last_access);
3284                         if (elapsed > aw->conn_ping_interval) {
3285                             k++;
3286                             /* handle cping/cpong.
3287                              */
3288                             if (ajp_handle_cping_cpong(aw->ep_cache[i],
3289                                 aw->ping_timeout, l) == JK_FALSE) {
3290                                 jk_log(l, JK_LOG_INFO,
3291                                        "(%s) failed sending request, "
3292                                        "socket %d keepalive cping/cpong "
3293                                        "failure (errno=%d)",
3294                                        aw->name,
3295                                        aw->ep_cache[i]->sd,
3296                                        aw->ep_cache[i]->last_errno);
3297                                 aw->ep_cache[i]->reuse = JK_FALSE;
3298                                 m_sock[m_count++] = aw->ep_cache[i]->sd;
3299                                 aw->ep_cache[i]->sd = JK_INVALID_SOCKET;
3300                                 ajp_reset_endpoint(aw->ep_cache[i], l);
3301                             }
3302                             else {
3303                                 now = time(NULL);
3304                                 aw->ep_cache[i]->last_access = now;
3305                             }
3306                         }
3307                     }
3308                 }
3309             }
3310             JK_LEAVE_CS(&aw->cs, rc);
3311             /* Shutdown sockets outside of the lock.
3312              * This has benefits only if maintain was
3313              * called from the watchdog thread.
3314              */
3315             for (m = 0; m < m_count; m++) {
3316                 jk_shutdown_socket(m_sock[m], l);
3317             }
3318             free(m_sock);
3319             if (n && JK_IS_DEBUG_LEVEL(l))
3320                 jk_log(l, JK_LOG_DEBUG,
3321                         "recycled %u sockets in %d seconds from %u pool slots",
3322                         n, (int)(difftime(time(NULL), mstarted)),
3323                         aw->ep_cache_sz);
3324             if (k && JK_IS_DEBUG_LEVEL(l))
3325                 jk_log(l, JK_LOG_DEBUG,
3326                         "pinged %u sockets in %d seconds from %u pool slots",
3327                         k, (int)(difftime(time(NULL), mstarted)),
3328                         aw->ep_cache_sz);
3329             JK_TRACE_EXIT(l);
3330             return JK_TRUE;
3331         }
3332         else {
3333            jk_log(l, JK_LOG_ERROR,
3334                   "locking thread (errno=%d)",
3335                   errno);
3336             JK_TRACE_EXIT(l);
3337             return JK_FALSE;
3338
3339         }
3340     }
3341     else {
3342         JK_LOG_NULL_PARAMS(l);
3343     }
3344
3345     JK_TRACE_EXIT(l);
3346     return JK_FALSE;
3347 }
3348
3349 int ajp_has_endpoint(jk_worker_t *pThis,
3350                      jk_logger_t *l)
3351 {
3352     JK_TRACE_ENTER(l);
3353
3354     if (pThis && pThis->worker_private) {
3355         ajp_worker_t *aw = pThis->worker_private;
3356         int rc;
3357
3358         JK_ENTER_CS(&aw->cs, rc);
3359         if (rc) {
3360             unsigned int slot;
3361             /* Try to find connected socket cache entry */
3362             for (slot = 0; slot < aw->ep_cache_sz; slot++) {
3363                 if (aw->ep_cache[slot]) {
3364                     JK_LEAVE_CS(&aw->cs, rc);
3365                     return JK_TRUE;
3366                 }
3367             }
3368             JK_LEAVE_CS(&aw->cs, rc);
3369         }
3370         else {
3371             jk_log(l, JK_LOG_ERROR,
3372                     "locking thread (errno=%d)", errno);
3373             JK_TRACE_EXIT(l);
3374             return JK_FALSE;
3375         }
3376     }
3377     else {
3378         JK_LOG_NULL_PARAMS(l);
3379     }
3380
3381     JK_TRACE_EXIT(l);
3382     return JK_FALSE;
3383 }