You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by hg...@apache.org on 2001/05/03 15:59:16 UTC

cvs commit: jakarta-tomcat/proposals/web-connector/native/common jk_ajp12_worker.c jk_ajp12_worker.h

hgomez      01/05/03 06:59:16

  Added:       proposals/web-connector/native/common jk_ajp12_worker.c
                        jk_ajp12_worker.h
  Log:
  ajp12 protocol handling
  
  Revision  Changes    Path
  1.1                  jakarta-tomcat/proposals/web-connector/native/common/jk_ajp12_worker.c
  
  Index: jk_ajp12_worker.c
  ===================================================================
  /*
   * Copyright (c) 1997-1999 The Java Apache Project.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Java Apache 
   *    Project for use in the Apache JServ servlet engine project
   *    <http://java.apache.org/>."
   *
   * 4. The names "Apache JServ", "Apache JServ Servlet Engine" and 
   *    "Java Apache Project" must not be used to endorse or promote products 
   *    derived from this software without prior written permission.
   *
   * 5. Products derived from this software may not be called "Apache JServ"
   *    nor may "Apache" nor "Apache JServ" appear in their names without 
   *    prior written permission of the Java Apache Project.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Java Apache 
   *    Project for use in the Apache JServ servlet engine project
   *    <http://java.apache.org/>."
   *    
   * THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Java Apache Group. For more information
   * on the Java Apache Project and the Apache JServ Servlet Engine project,
   * please see <http://java.apache.org/>.
   *
   */
  
  /***************************************************************************
   * Description: ajpv1.2 worker, used to call local or remote jserv hosts   *
   * Author:      Gal Shachor <sh...@il.ibm.com>                           *
   * Based on:    jserv_ajpv12.c from Jserv                                  *
   * Version:     $Revision: 1.1 $                                               *
   ***************************************************************************/
  
  #include "jk_ajp12_worker.h"
  #include "jk_pool.h"
  #include "jk_connect.h"
  #include "jk_util.h"
  #include "jk_sockbuf.h"
  
  #define AJP_DEF_HOST            ("localhost")
  #define AJP_DEF_PORT            (8007)
  #define READ_BUF_SIZE           (8*1024)
  #define DEF_RETRY_ATTEMPTS      (1)
  
  struct ajp12_worker {
      struct sockaddr_in worker_inet_addr;
      unsigned connect_retry_attempts;
      char *name; 
      jk_worker_t worker;
  };
  
  typedef struct ajp12_worker ajp12_worker_t;
  
  struct ajp12_endpoint { 
      ajp12_worker_t *worker;
      
      int sd;
      jk_sockbuf_t sb;
  
      jk_endpoint_t endpoint;
  };
  typedef struct ajp12_endpoint ajp12_endpoint_t;
  
  static int ajpv12_mark(ajp12_endpoint_t *p, 
                         unsigned char type);
  
  static int ajpv12_sendstring(ajp12_endpoint_t *p, 
                               const char *buffer);
  
  static int ajpv12_sendint(ajp12_endpoint_t *p, 
                            int d);
  
  static int ajpv12_sendnbytes(ajp12_endpoint_t *p, 
                               const void *buffer, 
                               int bufferlen);
  
  static int ajpv12_flush(ajp12_endpoint_t *p);
  
  static int ajpv12_handle_response(ajp12_endpoint_t *p, 
                                    jk_ws_service_t *s,
                                    jk_logger_t *l);
  
  static int ajpv12_handle_request(ajp12_endpoint_t *p, 
                                   jk_ws_service_t *s,
                                   jk_logger_t *l);
  
  static int JK_METHOD service(jk_endpoint_t *e, 
                               jk_ws_service_t *s,
                               jk_logger_t *l,
                               int *is_recoverable_error)
  {
      jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::service\n");
  
      if(e && e->endpoint_private && s && is_recoverable_error) {
          ajp12_endpoint_t *p = e->endpoint_private;
          unsigned attempt;
  
          *is_recoverable_error = JK_TRUE;
  
          for(attempt = 0 ; attempt < p->worker->connect_retry_attempts ; attempt++) {
              p->sd = jk_open_socket(&p->worker->worker_inet_addr, 
                                     JK_TRUE, 
                                     l);
  
              jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sd = %d\n", p->sd);
              if(p->sd >= 0) {
                  break;
              }
          }
          if(p->sd >= 0) {
  
              /*
               * After we are connected, each error that we are going to
               * have is probably unrecoverable
               */
              *is_recoverable_error = JK_FALSE;
              jk_sb_open(&p->sb, p->sd);
              if(ajpv12_handle_request(p, s, l)) {
                  jk_log(l, JK_LOG_DEBUG, "In jk_endpoint_t::service, sent request\n");
                  return ajpv12_handle_response(p, s, l);
              }                        
          }
          jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, Error sd = %d\n", p->sd);
      } else {
          jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::service, NULL parameters\n");
      }
  
      return JK_FALSE;
  }
  
  static int JK_METHOD done(jk_endpoint_t **e,
                            jk_logger_t *l)
  {
      jk_log(l, JK_LOG_DEBUG, "Into jk_endpoint_t::done\n");
      if(e && *e && (*e)->endpoint_private) {
          ajp12_endpoint_t *p = (*e)->endpoint_private;
          if(p->sd > 0) {
              jk_close_socket(p->sd);
          }
          free(p);
          *e = NULL;
          return JK_TRUE;
      }
  
      jk_log(l, JK_LOG_ERROR, "In jk_endpoint_t::done, NULL parameters\n");
      return JK_FALSE;
  }
  
  static int JK_METHOD validate(jk_worker_t *pThis,
                                jk_map_t *props,                            
                                jk_logger_t *l)
  {
      jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::validate\n");
  
      if(pThis && pThis->worker_private) {        
          ajp12_worker_t *p = pThis->worker_private;
          int port = jk_get_worker_port(props, 
                                        p->name,
                                        AJP_DEF_PORT);
  
          char *host = jk_get_worker_host(props, 
                                          p->name,
                                          AJP_DEF_HOST);
  
          jk_log(l, JK_LOG_DEBUG, "In jk_worker_t::validate for worker %s contact is %s:%d\n", 
                 p->name, host, port);
  
          if(port > 1024 && host) {
              if(jk_resolve(host, (short)port, &p->worker_inet_addr)) {
                  return JK_TRUE;
              }
              jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, resolve failed\n");
          }
          jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, Error %s %d\n", host, port);
      } else {
          jk_log(l, JK_LOG_ERROR, "In jk_worker_t::validate, NULL parameters\n");
      }
  
      return JK_FALSE;
  }
  
  static int JK_METHOD init(jk_worker_t *pThis,
                            jk_map_t *props, 
                            jk_logger_t *log)
  {
      /* Nothing to do for now */
      return JK_TRUE;
  }
  
  static int JK_METHOD get_endpoint(jk_worker_t *pThis,
                                    jk_endpoint_t **pend,
                                    jk_logger_t *l)
  {
      jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::get_endpoint\n");
  
      if(pThis && pThis->worker_private && pend) {        
          ajp12_endpoint_t *p = (ajp12_endpoint_t *)malloc(sizeof(ajp12_endpoint_t));
          if(p) {
              p->sd = -1;         
              p->worker = pThis->worker_private;
              p->endpoint.endpoint_private = p;
              p->endpoint.service = service;
              p->endpoint.done = done;
              *pend = &p->endpoint;
              return JK_TRUE;
          }
          jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, malloc failed\n");
      } else {
          jk_log(l, JK_LOG_ERROR, "In jk_worker_t::get_endpoint, NULL parameters\n");
      }
  
      return JK_FALSE;
  }
  
  static int JK_METHOD destroy(jk_worker_t **pThis,
                               jk_logger_t *l)
  {
      jk_log(l, JK_LOG_DEBUG, "Into jk_worker_t::destroy\n");
      if(pThis && *pThis && (*pThis)->worker_private) {
          ajp12_worker_t *private_data = (*pThis)->worker_private;
          free(private_data->name);
          free(private_data);
  
          return JK_TRUE;
      }
  
      jk_log(l, JK_LOG_ERROR, "In jk_worker_t::destroy, NULL parameters\n");
      return JK_FALSE;
  }
  
  int JK_METHOD ajp12_worker_factory(jk_worker_t **w,
                                     const char *name,
                                     jk_logger_t *l)
  {
      jk_log(l, JK_LOG_DEBUG, "Into ajp12_worker_factory\n");
      if(NULL != name && NULL != w) {
          ajp12_worker_t *private_data = 
              (ajp12_worker_t *)malloc(sizeof(ajp12_worker_t));
  
          if(private_data) {
              private_data->name = strdup(name);          
  
              if(private_data->name) {
                  private_data->connect_retry_attempts= DEF_RETRY_ATTEMPTS;
                  private_data->worker.worker_private = private_data;
  
                  private_data->worker.validate       = validate;
                  private_data->worker.init           = init;
                  private_data->worker.get_endpoint   = get_endpoint;
                  private_data->worker.destroy        = destroy;
  
                  *w = &private_data->worker;
                  return JK_TRUE;
              }
  
              free(private_data);
          } 
          jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, malloc failed\n");
      } else {
          jk_log(l, JK_LOG_ERROR, "In ajp12_worker_factory, NULL parameters\n");
      }
  
      return JK_FALSE;
  }
  
  static int ajpv12_sendnbytes(ajp12_endpoint_t *p, 
                               const void *buffer, 
                               int bufferlen) 
  {
      unsigned char bytes[2];
      static const unsigned char null_b[2] = { (unsigned char)0xff, (unsigned char)0xff };
  
      if(buffer) {
          bytes[0] = (unsigned char) ( (bufferlen >> 8) & 0xff );
          bytes[1] = (unsigned char) ( bufferlen & 0xff );
  
          if(jk_sb_write(&p->sb, bytes, 2)) {
              return jk_sb_write(&p->sb, buffer, bufferlen);
          } else {
              return JK_FALSE;
          }
      } else {
          return jk_sb_write(&p->sb, null_b, 2);
      }
  }
  
  static int ajpv12_sendstring(ajp12_endpoint_t *p, 
                               const char *buffer) 
  {
      int bufferlen;
  
      if(buffer && (bufferlen = strlen(buffer))) {
          return ajpv12_sendnbytes(p, buffer, bufferlen);
      } else {
          return ajpv12_sendnbytes(p, NULL, 0);
      }
  }
  
  static int ajpv12_mark(ajp12_endpoint_t *p, 
                         unsigned char type) 
  {
      if(jk_sb_write(&p->sb, &type, 1)) {
          return JK_TRUE;
      } else {
          return JK_FALSE;
      }
  }
  
  static int ajpv12_sendint(ajp12_endpoint_t *p, 
                            int d)
  {
      char buf[20];
      sprintf(buf, "%d", d);
      return ajpv12_sendstring(p, buf);
  }
  
  static int ajpv12_flush(ajp12_endpoint_t *p)
  {
      return jk_sb_flush(&p->sb);
  }
  
  static int ajpv12_handle_request(ajp12_endpoint_t *p, 
                                   jk_ws_service_t *s,
                                   jk_logger_t *l) 
  {
      int ret;
  
      jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_request\n");
      /*
       * Start the ajp 12 service sequence
       */
      jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the ajp12 start sequence\n");
      
      ret = (ajpv12_mark(p, 1) &&
             ajpv12_sendstring(p, s->method) &&
             ajpv12_sendstring(p, 0) &&   /* zone */
             ajpv12_sendstring(p, 0) &&   /* servlet */
             ajpv12_sendstring(p, s->server_name) &&
             ajpv12_sendstring(p, 0) &&   /* doc root */
             ajpv12_sendstring(p, 0) &&   /* path info */
             ajpv12_sendstring(p, 0) &&   /* path translated */
             ajpv12_sendstring(p, s->query_string)&&
             ajpv12_sendstring(p, s->remote_addr) &&
             ajpv12_sendstring(p, s->remote_host) &&
             ajpv12_sendstring(p, s->remote_user) &&
             ajpv12_sendstring(p, s->auth_type)   &&
             ajpv12_sendint(p, s->server_port)    &&
             ajpv12_sendstring(p, s->method)      &&
             ajpv12_sendstring(p, s->req_uri)     &&
             ajpv12_sendstring(p, 0)              && /* */
             ajpv12_sendstring(p, 0)              && /* SCRIPT_NAME */
             ajpv12_sendstring(p, s->server_name) &&
             ajpv12_sendint(p, s->server_port)    &&
             ajpv12_sendstring(p, s->protocol)    &&
             ajpv12_sendstring(p, 0)              && /* SERVER_SIGNATURE */ 
             ajpv12_sendstring(p, s->server_software) &&
             ajpv12_sendstring(p, s->jvm_route)   && /* JSERV_ROUTE */
             ajpv12_sendstring(p, "")             && /* JSERV ajpv12 compatibility */
             ajpv12_sendstring(p, ""));              /* JSERV ajpv12 compatibility */
  
      if(!ret) {
          jk_log(l, JK_LOG_ERROR, 
                "In ajpv12_handle_request, failed to send the ajp12 start sequence\n");
          return JK_FALSE;
      }
  
      if(s->num_attributes > 0) {
          unsigned  i;
          jk_log(l, JK_LOG_DEBUG, 
                 "ajpv12_handle_request, sending the environment variables\n");
      
          for(i = 0 ; i < s->num_attributes ; i++) {
              ret = (ajpv12_mark(p, 5)                            &&
  	    	       ajpv12_sendstring(p, s->attributes_names[i]) &&
  		           ajpv12_sendstring(p, s->attributes_values[i]));
              if(!ret) {
                  jk_log(l, JK_LOG_ERROR, 
                         "In ajpv12_handle_request, failed to send environment\n");
                  return JK_FALSE;
              }
          }
      }
  
      jk_log(l, JK_LOG_DEBUG, 
             "ajpv12_handle_request, sending the headers\n");
  
      /* Send the request headers */
      if(s->num_headers) {
          unsigned  i;
          for(i = 0 ; i < s->num_headers ; ++i) {
              ret = (ajpv12_mark(p, 3) &&
                     ajpv12_sendstring(p, s->headers_names[i]) &&
                     ajpv12_sendstring(p, s->headers_values[i]) );
  
              if(!ret) {
                  jk_log(l, JK_LOG_ERROR, 
                         "In ajpv12_handle_request, failed to send headers\n");
                  return JK_FALSE;
              }
          }
      }
  
      jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the terminating mark\n");
  
      ret =  (ajpv12_mark(p, 4) && ajpv12_flush(p));
      if(!ret) {
          jk_log(l, JK_LOG_ERROR, 
                 "In ajpv12_handle_request, failed to send the terminating mark\n");
          return JK_FALSE;
      }
  
      if(s->content_length) {
          char buf[READ_BUF_SIZE];
          unsigned so_far = 0;
  
          jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sending the request body\n");
  
          while(so_far < s->content_length) {
              unsigned this_time = 0;
              unsigned to_read = s->content_length - so_far;
              if(to_read > READ_BUF_SIZE) {
                  to_read = READ_BUF_SIZE;
              }
  
              if(!s->read(s, buf, to_read, &this_time)) {
                  jk_log(l, JK_LOG_ERROR, 
                         "In ajpv12_handle_request, failed to read from the web server\n");
                  return JK_FALSE;
              }
              jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, read %d bytes\n", this_time);
              if(this_time > 0) {
                  so_far += this_time;
                  if((int)this_time != send(p->sd, buf, this_time, 0)) {
                      jk_log(l, JK_LOG_ERROR, 
                             "In ajpv12_handle_request, failed to write to the container\n");
                      return JK_FALSE;
                  }
                  jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request, sent %d bytes\n", this_time);
              } else if (this_time == 0) {
               jk_log(l, JK_LOG_ERROR,
                       "In ajpv12_handle_request, Error: short read. content length is %d, read %d\n",
                       s->content_length, so_far);
               return JK_FALSE;
              }
          }
      }
  
      jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_request done\n");
      return JK_TRUE;
  }
  
  static int ajpv12_handle_response(ajp12_endpoint_t *p, 
                                    jk_ws_service_t *s,
                                    jk_logger_t *l) 
  {
      int status      = 200;
      char *reason    = NULL;
      char **names    = NULL;
      char **values   = NULL;
      int  headers_capacity = 0;
      int  headers_len = 0;
      int  write_to_ws;
  
      jk_log(l, JK_LOG_DEBUG, "Into ajpv12_handle_response\n");
      /*
       * Read headers ...
       */
      while(1) {
          char *line  = NULL;
          char *name  = NULL;
          char *value = NULL;
  
          if(!jk_sb_gets(&p->sb, &line)) {
              jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error reading header line\n");
              return JK_FALSE;
          }
          
          jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s\n", line);
          if(0 == strlen(line)) {
              jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, headers are done\n");
              break;      /* Empty line -> end of headers */
          }
  
          name = line;
          while(isspace(*name) && *name) {
              name++;     /* Skip leading white chars */
          }
          if(!*name) {    /* Empty header name */
              jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, empty header name\n");
              return JK_FALSE;
          }
          if(!(value = strchr(name, ':'))) { 
              jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, no value supplied\n");
              return JK_FALSE; /* No value !!! */
          }
          *value = '\0';
          value++;
          while(isspace(*value) && *value) { 
              value++;    /* Skip leading white chars */
          }
          if(!*value) {   /* Empty header value */
              jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, empty header value\n");
              return JK_FALSE;
          }
  
          jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, read %s=%s\n", name, value);
          if(0 == strcmp("Status", name)) {
              char *numeric = strtok(value, " \t");
  
              status = atoi(numeric);
              if(status < 100 || status > 999) {
                  jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, invalid status code\n");
                  return JK_FALSE;
              }
              reason = strtok(NULL, " \t");
          } else {
              if(headers_capacity == headers_len) {
                  jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, allocating header arrays\n");
                  names = (char **)jk_pool_realloc(s->pool,  
                                                   sizeof(char *) * (headers_capacity + 5),
                                                   names,
                                                   sizeof(char *) * headers_capacity);
                  values = (char **)jk_pool_realloc(s->pool,  
                                                    sizeof(char *) * (headers_capacity + 5),
                                                    values,
                                                    sizeof(char *) * headers_capacity);
                  if(!values || !names) {
                      jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, malloc error\n");
                      return JK_FALSE;
                  }
                  headers_capacity = headers_capacity + 5;
              }
              names[headers_len] = jk_pool_strdup(s->pool, name);
              values[headers_len] = jk_pool_strdup(s->pool, value);
              headers_len++;
          }
      }
  
      jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, starting response\n");
      if(!s->start_response(s, 
                            status, 
                            reason, 
                            (const char * const *)names, 
                            (const char * const *)values, 
                            headers_len)) {
          jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error starting response\n");
          return JK_FALSE;
      }
  
      jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, reading response body\n");
      /*
       * Read response body
       */
      write_to_ws = JK_TRUE;
      while(1) {
          unsigned to_read = READ_BUF_SIZE;
          unsigned acc = 0;
          char *buf = NULL;
      
          if(!jk_sb_read(&p->sb, &buf, to_read, &acc)) {
              jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error reading from \n");
              return JK_FALSE;
          }
  
          if(!acc) {
              jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response, response body is done\n");
              break;
          }
  
          if(write_to_ws) {
              if(!s->write(s, buf, acc)) {
                  jk_log(l, JK_LOG_ERROR, "ajpv12_handle_response, error writing back to server\n");
                  write_to_ws = JK_FALSE;
              }
          }
      }
  
      jk_log(l, JK_LOG_DEBUG, "ajpv12_handle_response done\n");
      return JK_TRUE;
  }
  
  
  
  1.1                  jakarta-tomcat/proposals/web-connector/native/common/jk_ajp12_worker.h
  
  Index: jk_ajp12_worker.h
  ===================================================================
  /*
   * Copyright (c) 1997-1999 The Java Apache Project.  All rights reserved.
   *
   * Redistribution and use in source and binary forms, with or without
   * modification, are permitted provided that the following conditions
   * are met:
   *
   * 1. Redistributions of source code must retain the above copyright
   *    notice, this list of conditions and the following disclaimer.
   *
   * 2. Redistributions in binary form must reproduce the above copyright
   *    notice, this list of conditions and the following disclaimer in
   *    the documentation and/or other materials provided with the
   *    distribution.
   *
   * 3. All advertising materials mentioning features or use of this
   *    software must display the following acknowledgment:
   *    "This product includes software developed by the Java Apache 
   *    Project for use in the Apache JServ servlet engine project
   *    <http://java.apache.org/>."
   *
   * 4. The names "Apache JServ", "Apache JServ Servlet Engine" and 
   *    "Java Apache Project" must not be used to endorse or promote products 
   *    derived from this software without prior written permission.
   *
   * 5. Products derived from this software may not be called "Apache JServ"
   *    nor may "Apache" nor "Apache JServ" appear in their names without 
   *    prior written permission of the Java Apache Project.
   *
   * 6. Redistributions of any form whatsoever must retain the following
   *    acknowledgment:
   *    "This product includes software developed by the Java Apache 
   *    Project for use in the Apache JServ servlet engine project
   *    <http://java.apache.org/>."
   *    
   * THIS SOFTWARE IS PROVIDED BY THE JAVA APACHE PROJECT "AS IS" AND ANY
   * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE JAVA APACHE PROJECT OR
   * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
   * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
   * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
   * OF THE POSSIBILITY OF SUCH DAMAGE.
   *
   * This software consists of voluntary contributions made by many
   * individuals on behalf of the Java Apache Group. For more information
   * on the Java Apache Project and the Apache JServ Servlet Engine project,
   * please see <http://java.apache.org/>.
   *
   */
  
  /***************************************************************************
   * Description: ajpv1.2 worker header file                                 *
   * Author:      Gal Shachor <sh...@il.ibm.com>                           *
   * Version:     $Revision: 1.1 $                                               *
   ***************************************************************************/
  
  #ifndef JK_AJP12_WORKER_H
  #define JK_AJP12_WORKER_H
  
  #include "jk_logger.h"
  #include "jk_service.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif /* __cplusplus */
  
  #define JK_AJP12_WORKER_NAME ("ajp12")
  
  int JK_METHOD ajp12_worker_factory(jk_worker_t **w,
                                     const char *name,
                                     jk_logger_t *l);
  
  #ifdef __cplusplus
  }
  #endif /* __cplusplus */
  
  #endif /* JK_AJP12_WORKER_H */