]> granicus.if.org Git - php/commitdiff
catch up with the latest release
authorGeorge Wang <gwang@php.net>
Wed, 19 Mar 2008 22:43:25 +0000 (22:43 +0000)
committerGeorge Wang <gwang@php.net>
Wed, 19 Mar 2008 22:43:25 +0000 (22:43 +0000)
sapi/litespeed/README
sapi/litespeed/lsapi_main.c
sapi/litespeed/lsapidef.h
sapi/litespeed/lsapilib.c
sapi/litespeed/lsapilib.h

index bd57f1f315b4c45480a6a07045ae71211cbe390b..3f138c21636c4bfc7128c788f5e58aef20fc2b02 100644 (file)
@@ -3,27 +3,27 @@ Introduction
 
 LiteSpeed SAPI module is a dedicated interface for PHP integration with
 LiteSpeed Web Server. LiteSpeed SAPI has similar architecture to the
-FastCGI SAPI with two major enhancements: better performance and
-support for dynamic PHP configuration changes through web server
+FastCGI SAPI with there major enhancements: better performance, dynamic 
+spawning and PHP configuration modification through web server
 configuration and .htaccess files.  
 
 Our simple benchmark test ("hello world") shows that PHP with
 LiteSpeed SAPI has 30% better performance over PHP with FastCGI SAPI,
 which is nearly twice the performance that Apache mod_php can deliver. 
  
-A major drawback of FastCGI PHP comparing to mod_php is that "php.ini"
-is the only way to set PHP configuration, and cannot be changed at
-runtime via configuration files like .htaccess files or web server's
-virtual host configuration. As FastCGI PHP is usually shared at server
-level by all virtual hosts, it is big security concern to use it in a
-shared hosting environment. LiteSpeed SAPI is carefully designed to
-address this issue. It accepts same flexible configuration overridden
-methods as those supported in mod_php. LiteSpeed SAPI also uses the
-same configuration directives as Apache mod_php. 
+A major drawback of FastCGI PHP comparing to Apache mod_php is lacking
+the flexibilities in PHP configurations. PHP configurations cannot be 
+changed at runtime via configuration files like .htaccess files or web
+server's virtual host configuration. In shared hosting environment, 
+each hosting account will has its own "open_basedir" overridden in 
+server configuration to enhance server security when mod_php is used.
+usually, FastCGI PHP is not an option in shared hosting environment 
+due to lacking of this flexibility. LiteSpeed SAPI is carefully designed
+to address this issue. PHP configurations can be modified the same way 
+as that in mod_php with the the same configuration directives. 
 
-Therefore, with above enhancements, LiteSpeed SAPI is highly
-recommended over FastCGI SAPI for using PHP with LiteSpeed web
-server. 
+PHP with LiteSpeed SAPI is highly recommended over FastCGI PHP for 
+PHP scripting with LiteSpeed web server. 
 
 
 Building PHP with LiteSpeed SAPI
@@ -44,6 +44,33 @@ has been configured to run PHP with LiteSpeed SAPI already, you just
 need to overwrite the old executable with this one and you are all
 set. 
 
+Start PHP from command line
+===========================
+
+Usually, lsphp is managed by LiteSpeed web server in a single server
+installation. lsphp can be used in clustered environment with one 
+LiteSpeed web server at the front, load balancing lsphp processes 
+running on multiple backend servers. In such environment, lsphp can be
+start manually from command with option "-b <socket_address>", socket 
+address can be IPv4, IPv6 or Unix Domain Socket address. 
+for example:
+
+    ./lsphp -b [::]:3000
+
+have lsphp bind to port 3000 on all IPv4 and IPv6 address,
+
+    ./lsphp -b *:3000
+
+have lsphp bind to port 300 on all IPv4 address.
+
+    ./lsphp -b 192.168.0.2:3000
+
+have lsphp bind to address 192.168.0.2:3000.
+
+    ./lsphp -b /tmp/lsphp_manual.sock
+
+have lsphp accept request on Unix domain socket "/tmp/lsphp_manual.sock"
+
 
 Using LiteSpeed PHP with LiteSpeed Web Server
 =============================================
@@ -59,11 +86,12 @@ LiteSpeed SAPI or vice versa.
 
 Brief instructions are as follow:
 
-1) Login to web admin interface, go to 'Server'->'Ext App' tab, add an
-   external application of type "LSAPI app", "Command" should be set
-   to a shell command that executes the PHP binary you just
-   built. "Instances" should be set to match the value of "Max
-   Connections".  
+1) Login to web administration interface, go to 'Server'->'Ext App' tab,
+   add an external application of type "LSAPI app", "Command" should be
+   set to a shell command that executes the PHP binary you just built. 
+   "Instances" should be set to "1". Add "LSAPI_CHILDREN" environment 
+   variable to match the value of "Max Connections". More tunable 
+   environment variable described below can be added. 
 
 2) Go to 'Server'->'Script Handler' tab, add a script handler
    configuration: set 'suffix' to 'php', 'Handler Type' to 'LiteSpeed
@@ -74,34 +102,113 @@ Brief instructions are as follow:
 3) Click 'Apply Changes' link on the top left of the page, then click 
    'graceful restart'. Now PHP is running with LiteSpeed SAPI. 
 
-Tuning
-------
+Tunings
+-------
 
-There are two environment variables that can be tweaked to control the
-behavior of LiteSpeed PHP.  
+There are a few environment variables that can be tweaked to control the
+behavior of LSAPI application.  
 
-PHP_LSAPI_CHILDREN  (no default)
+* LSAPI_CHILDREN or PHP_LSAPI_CHILDREN  (default: 0)
 
-In order to handle multiple requests concurrently, LiteSpeed web
-server can either spawn multiple PHP processes; or spawn one process,
-and this process will create a number of child processes to handle
-multiple requests simultaneously. 
+There are two ways to let PHP handle multiple requests concurrently, 
+Server Managed Mode and Self Managed Mode. In Server Managed Mode, 
+LiteSpeed web server dynamically spawn/stop PHP processes, in this mode
+"Instances" should match "Max Connections" configuration for PHP 
+external application. To start PHP in Self Managed Mode, "Instances" 
+should be set to "1", while "LSAPI_CHILDREN" environment variable should
+be set to match the value of "Max Connections" and >1. Web Server will 
+start one PHP process, this process will start/stop children PHP processes 
+dynamically based on on demand. If "LSAPI_CHILDREN" <=1, PHP will be 
+started in server managed mode.
 
-The web server will create PHP processes specified by "Instance" in
-LSAPI application configuration. For one PHP process launched by the
-server, if PHP_LSAPI_CHILDREN is not set, it will not create any child
-process; if PHP_LSAPI_CHILDREN is set, it will spawn a number of child
-processes specified by PHP_LSAPI_CHILDREN. Usually, it should match
-"Max Connections" configured for the LSAPI application, and both
-values should not be set over 100 in most cases. 
+Self Managed Mode is preferred because all PHP processes can share one 
+shared memory block for the opcode cache.
 
-PHP_LSAPI_MAX_REQUESTS (default value: 500)
+Usually, there is no need to set value of LSAPI_CHILDREN over 100 in
+most server environment. 
+
+
+* LSAPI_AVOID_FORK              (default: 0)
+
+LSAPI_AVOID_FORK specifies the policy of the internal process manager in
+"Self Managed Mode". When set to 0, the internal process manager will stop
+and start children process on demand to save system resource. This is
+preferred in a shared hosting environment. When set to 1, the internal
+process manager will try to avoid freqently stopping and starting children
+process. This might be preferred in a dedicate hosting environment.
+
+
+* LSAPI_EXTRA_CHILDREN          (default: 1/3 of LSAPI_CHILDREN or 0)
+
+LSAPI_EXTRA_CHILDREN controls the maximum number of extra children processes
+can be started when some or all existing children processes are in
+malfunctioning state. Total number of children processes will be reduced to
+LSAPI_CHILDREN level as soon as service is back to normal.
+When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of
+LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value is 0.
+
+
+* LSAPI_MAX_REQS or PHP_LSAPI_MAX_REQUESTS (default value: 10000)
 
 This controls how many requests each child process will handle before
-exit. When one process exits, another will be created. This tuning is
-necessary because several PHP functions have been identified having
-memory leaks. If the PHP processes were left around forever, they
-could become very inefficient. 
+it exits automatically. Several PHP functions have been identified 
+having memory leaks. This parameter can help reducing memory usage 
+of leaky PHP functions. 
+
+
+* LSAPI_MAX_IDLE                (default value: 300 seconds)
+
+In Self Managed Mode, LSAPI_MAX_IDLE controls how long a idle child  
+process will wait for a new request before it exits. This option help 
+releasing system resources taken by idle processes.
+
+
+* LSAPI_MAX_IDLE_CHILDREN
+    (default value: 1/3 of LSAPI_CHILDREN or LSAPI_CHILDREN)
+
+In Self Managed Mode, LSAI_MAX_IDLE_CHILDREN controls how many idle 
+children processes are allowed. Excessive idle children processes
+will be killed by the parent process immediately.
+When LSAPI_AVOID_FORK is set to 0, the default value is 1/3 of
+LSAPI_CHIDLREN, When LSAPI_AVOID_FORK is set to 1, the default value
+is LSAPI_CHILDREN.
+
+
+* LSAPI_MAX_PROCESS_TIME        (default value: 300 seconds)
+
+In Self Managed Mode, LSAPI_MAX_PROCESS_TIME controls the maximum 
+processing time allowed when processing a request. If a child process
+can not finish processing of a request in the given time period, it 
+will be killed by the parent process. This option can help getting rid 
+of dead or runaway child process.
+
+
+* LSAPI_PGRP_MAX_IDLE           (default value: FOREVER )
+
+In Self Managed Mode, LSAPI_PGRP_MAX_IDLE controls how long the parent
+process will wait before exiting when there is no child process.
+This option help releasing system resources taken by an idle parent 
+process.
+
+
+* LSAPI_PPID_NO_CHECK
+
+By default a LSAPI application check the existence of its parent process
+and exits automatically if the parent process died. This is to reduce 
+orphan process when web server is restarted. However, it is desireable 
+to disable this feature, such as when a LSAPI process was started 
+manually from command line. LSAPI_PPID_NO_CHECK should be set when 
+you want to disable the checking of existence of parent process.
+When PHP started by "-b" option, it is disabled automatically. 
+
+
+Compatibility with Apache mod_php
+=================================
+
+LSAPI PHP supports PHP configuration overridden via web server configuration 
+as well as .htaccess. 
+Since 4.0 release "apache_response_headers" function is supported.
+
 
 
 Contact
index c8c84201c5c6dc03a9d3136d110a99e966d2cee2..3dc00caa2d0dcdd381bc7bbe60d534fdc2096e39 100644 (file)
@@ -23,6 +23,7 @@
 #include "php_ini.h"
 #include "php_variables.h"
 #include "zend_highlight.h"
+#include "zend.h"
 
 #include "lsapilib.h"
 
 
 
 #define SAPI_LSAPI_MAX_HEADER_LENGTH 2048
-static char s_headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
 
 static int  lsapi_mode       = 1;
 static char *php_self        = "";
 static char *script_filename = "";
+static int  source_highlight = 0;
 
 #ifdef ZTS
 zend_compiler_globals    *compiler_globals;
@@ -69,6 +70,7 @@ sapi_globals_struct      *sapi_globals;
 void ***tsrm_ls;
 #endif
 
+zend_module_entry litespeed_module_entry;
 
 /* {{{ php_lsapi_startup
  */
@@ -233,20 +235,22 @@ static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
 
         h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
         while (h) {
-            LSAPI_AppendRespHeader(h->header, h->header_len);
+            if ( h->header_len > 0 )
+                LSAPI_AppendRespHeader(h->header, h->header_len);
             h = zend_llist_get_next_ex(&sapi_headers->headers, &pos);
         }
         if (SG(sapi_headers).send_default_content_type)
         {
             char    *hd;
             int     len;
+            char    headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
 
             hd = sapi_get_default_content_type(TSRMLS_C);
-            len = snprintf( s_headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1,
+            len = snprintf( headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1,
                             "Content-type: %s", hd );
             efree(hd);
 
-            LSAPI_AppendRespHeader( s_headerBuf, len );
+            LSAPI_AppendRespHeader( headerBuf, len );
         }
     }
     LSAPI_FinalizeRespHeaders();
@@ -322,7 +326,9 @@ static int init_request_info( TSRMLS_D )
     SG(request_info).request_uri = LSAPI_GetScriptName();
     SG(request_info).content_length = LSAPI_GetReqBodyLen();
     SG(request_info).path_translated = LSAPI_GetScriptFileName();
-    SG(sapi_headers).http_response_code = 0;    //It is not reset by zend engine, set it to 0.
+
+    /* It is not reset by zend engine, set it to 0. */
+    SG(sapi_headers).http_response_code = 0;
     
     pAuth = LSAPI_GetHeader( H_AUTHORIZATION );
     php_handle_auth_data(pAuth TSRMLS_CC);
@@ -397,7 +403,7 @@ static int processReq( TSRMLS_D )
 
         override_ini();
 
-        if ( lsapi_module_main( 0 TSRMLS_CC ) == -1 )
+        if ( lsapi_module_main( source_highlight TSRMLS_CC ) == -1 )
             ret = -1;
 
     } zend_end_try();
@@ -408,27 +414,28 @@ static void cli_usage( TSRMLS_D )
 {
     static const char * usage =
         "Usage: php\n"
-        "       php -[h|i|q|v|?] [<file>] [args...]\n"
-        "  Run in LSAPI mode when no parameter or only '-c' is specified\n"
-        "  Run in Command Line Interpreter mode when parameters are specified"
+        "       php -[b|c|h|i|q|s|v|?] [<file>] [args...]\n"
+        "  Run in LSAPI mode, only '-b', '-s' and '-c' are effective\n"
+        "  Run in Command Line Interpreter mode when parameters are specified\n"
         "\n"
+        "  -b <address:port>|<port> Bind Path for external LSAPI Server mode\n"
         "  -c <path>|<file> Look for php.ini file in this directory\n"
         "  -h               This help\n"
         "  -i               PHP information\n"
         "  -q               Quiet-mode.  Suppress HTTP Header output.\n"
+        "  -s               Display colour syntax highlighted source.\n"
         "  -v               Version number\n"
         "  -?               This help\n"
         "\n"
         "  args...          Arguments passed to script.\n";
     php_output_startup();
     php_output_activate(TSRMLS_C);
-//    SG(headers_sent) = 1;
     php_printf( usage );
     php_end_ob_buffers(1 TSRMLS_CC);
 }
 
 static int parse_opt( int argc, char * argv[], int *climode,
-                        char **php_ini_path )
+                        char **php_ini_path, char ** php_bind )
 {
     char ** p = &argv[1];
     char ** argend= &argv[argc];
@@ -439,6 +446,15 @@ static int parse_opt( int argc, char * argv[], int *climode,
         ++p;
         switch( c )
         {
+        case 'b':
+            if ( p >= argend )
+            {
+                fprintf( stderr, "TCP or socket address must be specified following '-b' option.\n");
+                return -1;
+            }
+            *php_bind = *p++;
+            break;
+            
         case 'c':
             if ( p >= argend )
             {
@@ -448,6 +464,9 @@ static int parse_opt( int argc, char * argv[], int *climode,
             }
             *php_ini_path = *p++;
             break;
+        case 's':
+            source_highlight = 1;
+            break;    
         case 'h':
         case 'i':
         case 'q':
@@ -514,14 +533,10 @@ static int cli_main( int argc, char * argv[] )
             switch( c )
             {
             case 'q':
-//                SG(headers_sent) = 1;
-//                SG(request_info).no_headers = 1;
                 break;
             case 'i':
                 if (php_request_startup(TSRMLS_C) != FAILURE)
                 {
-//                    SG(headers_sent) = 1;
-//                    SG(request_info).no_headers = 1;
                     php_print_info(0xFFFFFFFF TSRMLS_CC);
                     php_end_ob_buffers(1 TSRMLS_CC);
                     php_request_shutdown( NULL );
@@ -531,8 +546,6 @@ static int cli_main( int argc, char * argv[] )
             case 'v':
                 if (php_request_startup(TSRMLS_C) != FAILURE)
                 {
-//                    SG(headers_sent) = 1;
-//                    SG(request_info).no_headers = 1;
 #if ZEND_DEBUG
                     php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2004 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
 #else
@@ -545,7 +558,10 @@ static int cli_main( int argc, char * argv[] )
                 break;
             case 'c':
                 ++p;
+            /* fall through */
+            case 's':
                 break;
+                
             case 'h':
             case '?':
             default:
@@ -580,12 +596,22 @@ static int cli_main( int argc, char * argv[] )
                     }
                     else
                     {
+                        if (source_highlight)
+                        {
+                            zend_syntax_highlighter_ini syntax_highlighter_ini;
+                    
+                            php_get_highlight_struct(&syntax_highlighter_ini);
+                            highlight_file(SG(request_info).path_translated, &syntax_highlighter_ini TSRMLS_CC);
+                        }
+                        else
+                        {
+                            file_handle.filename = *p;
+                            file_handle.free_filename = 0;
+                            file_handle.opened_path = NULL;
+
+                            php_execute_script(&file_handle TSRMLS_CC);
+                        }
 
-                        file_handle.filename = *p;
-                        file_handle.free_filename = 0;
-                        file_handle.opened_path = NULL;
-
-                        php_execute_script(&file_handle TSRMLS_CC);
                         php_request_shutdown( NULL );
                     }
                 }
@@ -667,7 +693,7 @@ void start_children( int children )
         pid = wait( &status );
         running--;
     }
-       kill( -getpgrp(), s_stop );
+       kill( -getpgrp(), SIGUSR1 );
     exit( 0 );
 }
 
@@ -677,12 +703,14 @@ void start_children( int children )
 int main( int argc, char * argv[] )
 {
     int ret;
-    int max_requests = 500;
-    int requests     = 0;
+    int bindFd;
 
     char * php_ini_path = NULL;
+    char * php_bind     = NULL;
+    char * p;
+    int n;
     int climode = 0;
-
+    
 #ifdef HAVE_SIGNAL_H
 #if defined(SIGPIPE) && defined(SIG_IGN)
     signal(SIGPIPE, SIG_IGN);
@@ -695,7 +723,7 @@ int main( int argc, char * argv[] )
 
     if (argc > 1 )
     {
-        if ( parse_opt( argc, argv, &climode, &php_ini_path ) == -1 )
+        if ( parse_opt( argc, argv, &climode, &php_ini_path, &php_bind ) == -1 )
             return 1;
     }
     if ( climode )
@@ -717,7 +745,7 @@ int main( int argc, char * argv[] )
     if ( php_ini_path )
         lsapi_sapi_module.php_ini_path_override = php_ini_path;
 
-    if (php_module_startup(&lsapi_sapi_module, NULL, 0) == FAILURE) {
+    if (php_module_startup(&lsapi_sapi_module, &litespeed_module_entry, 1) == FAILURE) {
 #ifdef ZTS
         tsrm_shutdown();
 #endif
@@ -729,37 +757,36 @@ int main( int argc, char * argv[] )
         return cli_main(argc, argv);
     }
 
-    if( getenv( "PHP_LSAPI_MAX_REQUESTS" ))
+    
+    if ( php_bind )
     {
-        max_requests = atoi( getenv( "PHP_LSAPI_MAX_REQUESTS" ));
-        if( !max_requests )
+        bindFd = LSAPI_CreateListenSock( php_bind, 10 );
+        if ( bindFd == -1 )
         {
             fprintf( stderr,
-                     "PHP_LSAPI_MAX_REQUESTS is not valid\n" );
-            exit( 1 );
+                     "Failed to bind socket [%s]: %s\n", php_bind, strerror( errno ) );
+            exit( 2 );
+        }
+        if ( bindFd != 0 )
+        {
+            dup2( bindFd, 0 );
+            close( bindFd );
         }
     }
-    
+
     LSAPI_Init();
+   
+    LSAPI_Init_Env_Parameters( NULL );
 
-    if (( getenv( "PHP_LSAPI_CHILDREN" ) )&& LSAPI_Is_Listen() )
-    {
-        int children = atoi( getenv( "PHP_LSAPI_CHILDREN" ));
-        if ( children > 0 )
-            start_children( children );
-    }
+    if ( php_bind )
+        LSAPI_No_Check_ppid();
 
-    while( LSAPI_Accept() >= 0 )
+    while( LSAPI_Prefork_Accept_r( &g_req ) >= 0 )
     {
         ret = processReq(TSRMLS_C);
         LSAPI_Finish();
         if ( ret )
             break;
-        requests++;
-        if( max_requests && ( requests == max_requests ))
-        {
-            break;
-        }
     }
     php_module_shutdown(TSRMLS_C);
 
@@ -769,6 +796,122 @@ int main( int argc, char * argv[] )
     return ret;
 }
 
+
+/*   LiteSpeed PHP module starts here */
+
+
+
+PHP_FUNCTION(litespeed_request_headers);
+PHP_FUNCTION(litespeed_response_headers);
+
+PHP_MINFO_FUNCTION(litespeed);
+
+zend_function_entry litespeed_functions[] = {
+       PHP_FE(litespeed_request_headers,                                       NULL)
+       PHP_FE(litespeed_response_headers,                                      NULL)
+       PHP_FALIAS(getallheaders, litespeed_request_headers, NULL)
+       PHP_FALIAS(apache_request_headers, litespeed_request_headers, NULL)
+       PHP_FALIAS(apache_response_headers, litespeed_response_headers, NULL)
+       {NULL, NULL, NULL}
+};
+
+static PHP_MINIT_FUNCTION(litespeed)
+{
+       //REGISTER_INI_ENTRIES();
+       return SUCCESS;
+}
+
+
+static PHP_MSHUTDOWN_FUNCTION(litespeed)
+{
+       //UNREGISTER_INI_ENTRIES();
+       return SUCCESS;
+}
+
+zend_module_entry litespeed_module_entry = {
+       STANDARD_MODULE_HEADER,
+       "litespeed",
+       litespeed_functions,
+       PHP_MINIT(litespeed),
+       PHP_MSHUTDOWN(litespeed),
+       NULL,
+       NULL,
+       NULL,
+       NO_VERSION_YET,
+       STANDARD_MODULE_PROPERTIES
+};
+
+static int add_associate_array( const char * pKey, int keyLen, const char * pValue, int valLen,
+                         void * arg )
+{
+    add_assoc_string_ex( (zval *)arg, (char *)pKey, keyLen+1, (char *)pValue, 1 );
+    return 1;
+}
+
+
+/* {{{ proto array litespeed_request_headers(void)
+   Fetch all HTTP request headers */
+PHP_FUNCTION(litespeed_request_headers)
+{
+    //TODO:
+    if (ZEND_NUM_ARGS() > 0) {
+        WRONG_PARAM_COUNT;
+    }
+    array_init(return_value);
+
+    LSAPI_ForeachOrgHeader( add_associate_array, return_value );
+
+}
+/* }}} */
+
+
+
+/* {{{ proto array litespeed_response_headers(void)
+   Fetch all HTTP response headers */
+PHP_FUNCTION(litespeed_response_headers)
+{
+    sapi_header_struct  *h;
+    zend_llist_position pos;
+    char *       p;
+    int          len;
+    char         headerBuf[SAPI_LSAPI_MAX_HEADER_LENGTH];
+
+    if (ZEND_NUM_ARGS() > 0) {
+               WRONG_PARAM_COUNT;
+       }
+
+       if (!&SG(sapi_headers).headers) {
+               RETURN_FALSE;
+       }
+       array_init(return_value);
+
+    h = zend_llist_get_first_ex(&SG(sapi_headers).headers, &pos);
+    while (h)
+    {
+        if ( h->header_len > 0 )
+        {
+            p = strchr( h->header, ':' );
+            len = p - h->header;
+            if (( p )&&( len > 0 ))
+            {
+                memmove( headerBuf, h->header, len );
+                while( len > 0 && (isspace( headerBuf[len-1])) )
+                    --len;
+                headerBuf[len] = 0;
+                if ( len )
+                {
+                    while( isspace(*++p));
+                    add_assoc_string_ex(return_value, headerBuf, len+1, p, 1 );
+                }
+            }
+        }
+        h = zend_llist_get_next_ex(&SG(sapi_headers).headers, &pos);
+    }  
+}
+
+/* }}} */
+
+
 /*
  * Local variables:
  * tab-width: 4
index 420f3ed3b49e0bafb81e84da21504ae20749f730..c7f0d20c62f056da522e880bb674bbe399d90040 100644 (file)
@@ -79,9 +79,9 @@ enum
 #define LSAPI_SOCK_FILENO           0
 
 #define LSAPI_VERSION_B0            'L'
-#define LSAPI_VERSION_B1            'S'                
+#define LSAPI_VERSION_B1            'S'
 
-//Values for m_flag in lsapi_packet_header
+/* Values for m_flag in lsapi_packet_header */
 #define LSAPI_ENDIAN_LITTLE         0
 #define LSAPI_ENDIAN_BIG            1 
 #define LSAPI_ENDIAN_BIT            1
@@ -92,7 +92,7 @@ enum
 #define LSAPI_ENDIAN                LSAPI_ENDIAN_BIG
 #endif
 
-//Values for m_type in lsapi_packet_header
+/* Values for m_type in lsapi_packet_header */
 #define LSAPI_BEGIN_REQUEST         1
 #define LSAPI_ABORT_REQUEST         2
 #define LSAPI_RESP_HEADER           3
@@ -111,24 +111,26 @@ enum
 
 struct lsapi_packet_header
 {
-    char    m_versionB0;      //LSAPI protocol version 
+    char    m_versionB0;      /* LSAPI protocol version */
     char    m_versionB1;
     char    m_type;
     char    m_flag;
     union
     {
-        int32_t m_iLen;    //include this header
+        int32_t m_iLen;       /* include this header */
         char    m_bytes[4];
     }m_packetLen;
 };
 
-// LSAPI request header packet
-//
-// 1. struct lsapi_req_header
-// 2. struct lsapi_http_header_index
-// 3. lsapi_header_offset * unknownHeaders
-// 4. org http request header
-// 5. request body if available
+/*
+    LSAPI request header packet
+    
+    1. struct lsapi_req_header
+    2. struct lsapi_http_header_index
+    3. lsapi_header_offset * unknownHeaders
+    4. org http request header
+    5. request body if available
+*/
 
 struct lsapi_req_header
 {
@@ -136,9 +138,9 @@ struct lsapi_req_header
         
     int32_t m_httpHeaderLen;
     int32_t m_reqBodyLen;
-    int32_t m_scriptFileOff;   //path to the script file.
-    int32_t m_scriptNameOff;   //decrypted URI, without pathinfo,
-    int32_t m_queryStringOff;  //Query string inside env 
+    int32_t m_scriptFileOff;   /* path to the script file. */
+    int32_t m_scriptNameOff;   /* decrypted URI, without pathinfo, */
+    int32_t m_queryStringOff;  /* Query string inside env */
     int32_t m_requestMethodOff;
     int32_t m_cntUnknownHeaders;
     int32_t m_cntEnv;
index 53232694e735d8b6a0ae6c348e91ce540c217324..8e85958200f999ceebe0adf99120de7b063bf5f2 100644 (file)
@@ -45,16 +45,20 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 #include <errno.h>
 #include <fcntl.h>
 
-//#include <arpa/inet.h>
-#include <sys/types.h>
+#include <arpa/inet.h>
+#include <netdb.h>
 #include <netinet/in.h>
 #include <netinet/tcp.h>
+#include <sys/un.h>
 #include <signal.h>
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
+#include <sys/mman.h>
 #include <sys/socket.h>
 #include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
 #include <unistd.h>
 
 #define LSAPI_ST_REQ_HEADER     1
@@ -68,7 +72,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
 static int g_inited = 0;
 static int g_running = 1;
-LSAPI_Request g_req;
+static int s_ppid;
+LSAPI_Request g_req = { -1, -1 };
 
 void Flush_RespBuf_r( LSAPI_Request * pReq );
 
@@ -76,17 +81,17 @@ static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] =
 {
     "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET",
     "HTTP_ACCEPT_ENCODING",
-    "HTTP_ACCEPT_LANG", "HTTP_AUTHORIZATION",
+    "HTTP_ACCEPT_LANGUAGE", "HTTP_AUTHORIZATION",
     "HTTP_CONNECTION", "CONTENT_TYPE",
     "CONTENT_LENGTH", "HTTP_COOKIE", "HTTP_COOKIE2",
     "HTTP_HOST", "HTTP_PRAGMA",
     "HTTP_REFERER", "HTTP_USER_AGENT",
-    "HTTP_CACHE_CTRL",
+    "HTTP_CACHE_CONTROL",
     "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH",
     "HTTP_IF_NONE_MATCH",
     "HTTP_IF_RANGE",
     "HTTP_IF_UNMODIFIED_SINCE",
-    "HTTP_KEEPALIVE",
+    "HTTP_KEEP_ALIVE",
     "HTTP_RANGE",
     "HTTP_X_FORWARDED_FOR",
     "HTTP_VIA",
@@ -94,9 +99,36 @@ static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] =
 };
      
 static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] =
-{    11, 19, 20, 16, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 15,
-     22, 13, 18, 13, 24, 14, 10, 20, 8, 22 };
+{    11, 19, 20, 20, 18, 15, 12, 14, 11, 12, 9, 11, 12, 15, 18,
+     22, 13, 18, 13, 24, 15, 10, 20, 8, 22 };
 
+
+static const char *HTTP_HEADERS[H_TRANSFER_ENCODING+1] =
+{
+    "Accept", "Accept-Charset",
+    "Accept-Encoding",
+    "Accept-Language", "Authorization",
+    "Connection", "Content-Type",
+    "Content-Length", "Cookie", "Cookie2",
+    "Host", "Pragma",
+    "Referer", "User-Agent",
+    "Cache-Control",
+    "If-Modified-Since", "If-Match",
+    "If-None-Match",
+    "If-Range",
+    "If-Unmodified-Since",
+    "Keep-Alive",
+    "Range",
+    "X-Forwarded-For",
+    "Via",
+    "Transfer-Encoding"
+};
+
+static int HTTP_HEADER_LEN[H_TRANSFER_ENCODING+1] =
+{   6, 14, 15, 15, 13, 10, 12, 14, 6, 7, 4, 6, 7, 10, //user-agent
+    13,17, 8, 13, 8, 19, 10, 5, 15, 3, 17
+};
+     
 static void lsapi_sigpipe( int sig )
 {
 }
@@ -128,7 +160,7 @@ static void lsapi_signal(int signo, sighandler_t handler)
 static inline void lsapi_buildPacketHeader( struct lsapi_packet_header * pHeader,
                                 char type, int len )
 {
-    pHeader->m_versionB0 = LSAPI_VERSION_B0;      //LSAPI protocol version
+    pHeader->m_versionB0 = LSAPI_VERSION_B0;  /* LSAPI protocol version */
     pHeader->m_versionB1 = LSAPI_VERSION_B1;
     pHeader->m_type      = type;
     pHeader->m_flag      = LSAPI_ENDIAN;
@@ -159,25 +191,27 @@ static inline int lsapi_read( int fd, void * pBuf, int len )
     }
 }
 
-//static int lsapi_write( int fd, const void * pBuf, int len )
-//{
-//    int ret;
-//    const char * pCur;
-//    const char * pEnd;
-//    if ( len == 0 )
-//        return 0;
-//    pCur = (const char *)pBuf;
-//    pEnd = pCur + len;
-//    while( g_running && (pCur < pEnd) )
-//    {
-//        ret = write( fd, pCur, pEnd - pCur );
-//        if ( ret >= 0)
-//            pCur += ret;
-//        else if (( ret == -1 )&&( errno != EINTR ))
-//            return ret;
-//    }
-//    return pCur - (const char *)pBuf;
-//}
+/*
+static int lsapi_write( int fd, const void * pBuf, int len )
+{
+   int ret;
+   const char * pCur;
+   const char * pEnd;
+   if ( len == 0 )
+       return 0;
+   pCur = (const char *)pBuf;
+   pEnd = pCur + len;
+   while( g_running && (pCur < pEnd) )
+   {
+       ret = write( fd, pCur, pEnd - pCur );
+       if ( ret >= 0)
+           pCur += ret;
+       else if (( ret == -1 )&&( errno != EINTR ))
+           return ret;
+   }
+   return pCur - (const char *)pBuf;
+}
+*/
 
 static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen )
 {
@@ -207,24 +241,35 @@ static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen )
                 }
             }
         }
-        else if (( ret == -1 )&&( errno != EINTR ))
-            return ret;
+        else if ( ret == -1 )
+        {
+            if ( errno == EAGAIN )
+            {
+                if ( totalLen - left > 0 )
+                    return totalLen - left;
+                else
+                    return -1;
+            }
+            else if ( errno != EINTR )
+                return ret;
+        }
     }
     return totalLen - left;
 }
 
-//static int getTotalLen( struct iovec * pVec, int count )
-//{
-//    struct iovec * pEnd = pVec + count;
-//    int total = 0;
-//    while( pVec < pEnd )
-//    {
-//        total += pVec->iov_len;
-//        ++pVec;
-//    }
-//    return total;
-//}
-
+/*
+static int getTotalLen( struct iovec * pVec, int count )
+{
+   struct iovec * pEnd = pVec + count;
+   int total = 0;
+   while( pVec < pEnd )
+   {
+       total += pVec->iov_len;
+       ++pVec;
+   }
+   return total;
+}
+*/
 
 static inline int allocateBuf( LSAPI_Request * pReq, int size )
 {
@@ -307,8 +352,8 @@ static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList,
 
 static inline int isPipe( int fd )
 {
-    char achPeer[128];
-    int len = 128;
+    char        achPeer[128];
+    socklen_t   len = 128;
     if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&&
         ( errno == ENOTCONN ))
         return 0;
@@ -503,9 +548,9 @@ static int readReq( LSAPI_Request * pReq )
     if ( packetLen > LSAPI_MAX_HEADER_LEN )
         return -1;
 
-    if ( packetLen > pReq->m_reqBufSize )
+    if ( packetLen + 1024 > pReq->m_reqBufSize )
     {
-        if ( allocateBuf( pReq, packetLen ) == -1 )
+        if ( allocateBuf( pReq, packetLen + 1024 ) == -1 )
             return -1;
     }
     while( packetLen > pReq->m_bufRead )
@@ -535,15 +580,21 @@ int LSAPI_Init(void)
         if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 )
             return -1;
         g_inited = 1;
+        s_ppid = getppid();
     }
     return 0;
 }
 
-void LSAPI_stop(void)
+void LSAPI_Stop(void)
 {
     g_running = 0;
 }
 
+int LSAPI_IsRunning(void)
+{
+    return g_running;
+}
+
 int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
 {
     if ( !pReq )
@@ -587,9 +638,10 @@ int LSAPI_Is_Listen_r( LSAPI_Request * pReq)
 
 int LSAPI_Accept_r( LSAPI_Request * pReq )
 {
-    char achPeer[128];
-    int  len;
-    int  nodelay = 1;
+    char        achPeer[128];
+    socklen_t   len;
+    int         nodelay = 1;
+    
     if ( !pReq )
         return -1;
     if ( LSAPI_Finish_r( pReq ) == -1 )
@@ -603,10 +655,14 @@ int LSAPI_Accept_r( LSAPI_Request * pReq )
                 len = sizeof( achPeer );
                 pReq->m_fd = accept( pReq->m_fdListen,
                             (struct sockaddr *)&achPeer, &len );
-                if (( pReq->m_fd == -1 )&&( errno == EINTR ))
-                    continue;
-                if (( pReq->m_fd != -1 )&&
-                    (((struct sockaddr *)&achPeer)->sa_family == AF_INET ))
+                if ( pReq->m_fd == -1 )
+                {
+                    if (( errno == EINTR )||( errno == EAGAIN))
+                        continue;
+                    else
+                        return -1;
+                }
+                else if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
                 {    
                     setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY,
                                 (char *)&nodelay, sizeof(nodelay));
@@ -629,7 +685,7 @@ static struct lsapi_packet_header   finish = {'L', 'S',
 
 int LSAPI_Finish_r( LSAPI_Request * pReq )
 {
-    //finish req body
+    /* finish req body */
     if ( !pReq )
         return -1;
     if (pReq->m_reqState)
@@ -697,14 +753,96 @@ char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex )
     return pReq->m_pHttpHeader + off;
 }
 
+static int readBodyToReqBuf( LSAPI_Request * pReq )
+{
+    int bodyLeft;
+    int len = pReq->m_bufRead - pReq->m_bufProcessed;
+    if ( len > 0 )
+        return len;
+    pReq->m_bufRead = pReq->m_bufProcessed = pReq->m_pHeader->m_pktHeader.m_packetLen.m_iLen;
+
+    bodyLeft = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
+    len = pReq->m_reqBufSize - pReq->m_bufRead;
+    if ( len < 0 )
+        return -1;
+    if ( len > bodyLeft )
+        len = bodyLeft;
+        
+    len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, len );
+    if ( len > 0 )
+        pReq->m_bufRead += len;
+    return len;
+}
+
+
+int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq )
+{
+    if (!pReq || (pReq->m_fd ==-1) )
+        return EOF;
+    if ( pReq->m_bufProcessed >= pReq->m_bufRead )
+    {
+        if ( readBodyToReqBuf( pReq ) <= 0 )
+            return EOF;
+    }
+    ++pReq->m_reqBodyRead;
+    return (unsigned char)*(pReq->m_pReqBuf + pReq->m_bufProcessed++);
+}
+
+
+
+int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, int bufLen, int *getLF )
+{
+    int len;
+    int left;
+    char * pBufEnd = pBuf + bufLen - 1;
+    char * pBufCur = pBuf;
+    char * pCur;
+    char * p;
+    if (!pReq || (pReq->m_fd ==-1) ||( !pBuf )||(bufLen < 0 )|| !getLF )
+        return -1;
+    *getLF = 0;
+    while( (left = pBufEnd - pBufCur ) > 0 )
+    {
+        
+        len = pReq->m_bufRead - pReq->m_bufProcessed;
+        if ( len <= 0 )
+        {
+            if ( (len = readBodyToReqBuf( pReq )) <= 0 )
+            {
+                *getLF = 1;
+                break;
+            }
+        }
+        if ( len > left )
+            len = left;
+        pCur = pReq->m_pReqBuf + pReq->m_bufProcessed;
+        p = memchr( pCur, '\n', len );
+        if ( p )
+            len = p - pCur + 1;
+        memmove( pBufCur, pCur, len );
+        pBufCur += len;
+        pReq->m_bufProcessed += len;
+
+        pReq->m_reqBodyRead += len;
+        
+        if ( p )
+        {
+            *getLF = 1;
+            break;
+        }
+    }
+    *pBufCur = 0;
+  
+    return pBufCur - pBuf;
+}
 
 
 int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen )
 {
     int len;
     int total;
-    //char *pOldBuf = pBuf;
-    if (!pReq || ( !pBuf )||(bufLen < 0 ))
+    /* char *pOldBuf = pBuf; */
+    if (!pReq || (pReq->m_fd ==-1) || ( !pBuf )||(bufLen < 0 ))
         return -1;
 
     total = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
@@ -735,8 +873,12 @@ int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen )
             pBuf += len;
             bufLen -= len;
         }
-        else if ( len < 0 )
-            return -1;
+        else if ( len <= 0 )
+        {
+            if ( !total)
+                return -1;
+            break;
+        }
     }
     pReq->m_reqBodyRead += total;
     return total;
@@ -744,11 +886,6 @@ int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int bufLen )
 }
 
 
-//int LSAPI_Write( const char * pBuf, int len )
-//{
-//    return LSAPI_Write_r( &g_req, pBuf, len );
-//}
-
 int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
 {
     struct lsapi_packet_header * pHeader;
@@ -758,7 +895,7 @@ int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
     int toWrite;
     int packetLen;
     
-    if ( !pReq || !pBuf )
+    if ( !pReq || !pBuf || (pReq->m_fd == -1) )
         return -1;
     if ( len < pReq->m_pRespBufEnd - pReq->m_pRespBufPos )
     {
@@ -854,6 +991,16 @@ int LSAPI_Flush_r( LSAPI_Request * pReq )
     int n;
     if ( !pReq )
         return -1;
+    n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
+    if (( 0 == n )&&( pReq->m_pRespBufPos == pReq->m_pRespBuf ))
+        return 0;
+    if ( pReq->m_fd == -1 )
+    {
+        pReq->m_pRespBufPos = pReq->m_pRespBuf;
+        pReq->m_totalLen = 0;
+        pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec;
+        return -1;
+    }
     if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER )
     {
         LSAPI_FinalizeRespHeaders_r( pReq );
@@ -862,6 +1009,7 @@ int LSAPI_Flush_r( LSAPI_Request * pReq )
     {
         Flush_RespBuf_r( pReq );
     }
+    
     n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
     if ( n > 0 )
     {
@@ -892,6 +1040,10 @@ int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
     struct iovec iov[2];
     struct iovec *pIov;
     
+    if ( !pReq )
+        return -1;
+    if (( pReq->m_fd == -1 )||(pReq->m_fd == pReq->m_fdListen ))
+        return write( 2, pBuf, len );
     if ( pReq->m_pRespBufPos != pReq->m_pRespBuf )
     {
         LSAPI_Flush_r( pReq );
@@ -930,6 +1082,48 @@ int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
     return p - pBuf;
 }
 
+static char * GetHeaderVar( LSAPI_Request * pReq, const char * name )
+{
+    int i;
+    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
+    {
+        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
+        {
+            if ( strcmp( name, CGI_HEADERS[i] ) == 0 )
+                return pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
+        }
+    }
+    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
+    {
+        const char *p;
+        char *pKey;
+        char *pKeyEnd;
+        int  keyLen;
+        struct lsapi_header_offset * pCur, *pEnd;
+        pCur = pReq->m_pUnknownHeader;
+        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
+        while( pCur < pEnd )
+        {
+            pKey = pReq->m_pHttpHeader + pCur->nameOff;
+            keyLen = pCur->nameLen;
+            pKeyEnd = pKey + keyLen;
+            p = &name[5];
+
+            while(( pKey < pKeyEnd )&&( *p ))
+            {
+                char ch = toupper( *pKey );
+                if ((ch != *p )||(( *p == '_' )&&( ch != '-')))
+                    break;
+                ++p; ++pKey;
+            }
+            if (( pKey == pKeyEnd )&& (!*p ))
+                return pReq->m_pHttpHeader + pCur->valueOff;
+            ++pCur;
+        }
+    }
+    return NULL;
+}
+
 
 char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name )
 {
@@ -937,6 +1131,10 @@ char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name )
     struct LSAPI_key_value_pair * pEnd = pBegin + pReq->m_pHeader->m_cntEnv;
     if ( !pReq || !name )
         return NULL;
+    if ( strncmp( name, "HTTP_", 5 ) == 0 )
+    {
+        return GetHeaderVar( pReq, name );
+    }
     while( pBegin < pEnd )
     {
         if ( strcmp( name, pBegin->pKey ) == 0 )
@@ -946,6 +1144,55 @@ char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name )
     return NULL;
 }
 
+int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq,
+            LSAPI_CB_EnvHandler fn, void * arg )
+{
+    int i;
+    int len = 0;
+    char * pValue;
+    int ret;
+    int count = 0;
+    if ( !pReq || !fn )
+        return -1;
+    for( i = 0; i < H_TRANSFER_ENCODING; ++i )
+    {
+        if ( pReq->m_pHeaderIndex->m_headerOff[i] )
+        {
+            len = pReq->m_pHeaderIndex->m_headerLen[i];
+            pValue = pReq->m_pHttpHeader + pReq->m_pHeaderIndex->m_headerOff[i];
+            *(pValue + len ) = 0;
+            ret = (*fn)( HTTP_HEADERS[i], HTTP_HEADER_LEN[i],
+                        pValue, len, arg );
+            ++count;
+            if ( ret <= 0 )
+                return ret;
+        }
+    }
+    if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 )
+    {
+        char *pKey;
+        int  keyLen;
+        struct lsapi_header_offset * pCur, *pEnd;
+        pCur = pReq->m_pUnknownHeader;
+        pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
+        while( pCur < pEnd )
+        {
+            pKey = pReq->m_pHttpHeader + pCur->nameOff;
+            keyLen = pCur->nameLen;
+
+            pValue = pReq->m_pHttpHeader + pCur->valueOff;
+            *(pValue + pCur->valueLen ) = 0;
+            ret = (*fn)( pKey, keyLen, 
+                        pValue, pCur->valueLen, arg );
+            if ( ret <= 0 )
+                return ret;
+            ++pCur;
+        }
+    }
+    return count + pReq->m_pHeader->m_cntUnknownHeaders;
+    
+}
+
 
 int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
             LSAPI_CB_EnvHandler fn, void * arg )
@@ -1004,8 +1251,8 @@ int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
 
             pValue = pReq->m_pHttpHeader + pCur->valueOff;
             *(pValue + pCur->valueLen ) = 0;
-            ret = (*fn)( achHeaderName, pCur->valueLen,
-                        pValue, len, arg );
+            ret = (*fn)( achHeaderName, keyLen, 
+                        pValue, pCur->valueLen, arg );
             if ( ret <= 0 )
                 return ret;
             ++pCur;
@@ -1114,14 +1361,805 @@ int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, char * pBuf, int len )
     memmove( pReq->m_pRespHeaderBufPos, pBuf, len );
     pReq->m_pRespHeaderBufPos += len;
     *pReq->m_pRespHeaderBufPos++ = 0;
-    ++len;  //add one byte padding for \0
+    ++len;  /* add one byte padding for \0 */
     pReq->m_respHeaderLen[pReq->m_respHeader.m_respInfo.m_cntHeaders] = len;
     ++pReq->m_respHeader.m_respInfo.m_cntHeaders;
     return 0;
 }
 
 
+int LSAPI_CreateListenSock2( const struct sockaddr * pServerAddr, int backlog )
+{
+    int ret;
+    int fd;
+    int flag = 1;
+    int addr_len;
+
+    switch( pServerAddr->sa_family )
+    {
+    case AF_INET:
+        addr_len = 16;
+        break;
+    case AF_INET6:
+        addr_len = sizeof( struct sockaddr_in6 );
+        break;
+    case AF_UNIX:
+        addr_len = sizeof( struct sockaddr_un );
+        unlink( ((struct sockaddr_un *)pServerAddr)->sun_path );
+        break;
+    default:
+        return -1;
+    }
+
+    fd = socket( pServerAddr->sa_family, SOCK_STREAM, 0 );
+    if ( fd == -1 )
+        return -1;
+
+    fcntl( fd, F_SETFD, FD_CLOEXEC );
+
+    if(setsockopt( fd, SOL_SOCKET, SO_REUSEADDR,
+                (char *)( &flag ), sizeof(flag)) == 0)
+    {
+        ret = bind( fd, pServerAddr, addr_len );
+        if ( !ret )
+        {
+            ret = listen( fd, backlog );
+            if ( !ret )
+                return fd;
+        }
+    }
+
+    ret = errno;
+    close(fd);
+    errno = ret;
+    return -1;
+
+}
+
+int LSAPI_ParseSockAddr( const char * pBind, struct sockaddr * pAddr )
+{
+    char achAddr[256];
+    char * p = achAddr;
+    char * pEnd;
+    struct addrinfo *res, hints;
+    int  doAddrInfo = 0;
+    int port;
+    
+    if ( !pBind )
+        return -1;
 
+    while( isspace( *p ) )
+        ++pBind;
+
+    strncpy( achAddr, pBind, 256 );
+
+    switch( *p )
+    {
+    case '/':
+        pAddr->sa_family = AF_UNIX;
+        strncpy( ((struct sockaddr_un *)pAddr)->sun_path, p,
+                sizeof(((struct sockaddr_un *)pAddr)->sun_path) );
+        return 0;
+
+    case '[':
+        pAddr->sa_family = AF_INET6;
+        ++p;
+        pEnd = strchr( p, ']' );
+        if ( !pEnd )
+            return -1;
+        *pEnd++ = 0;
+        
+        if ( *p == '*' )
+        {
+            strcpy( achAddr, "::" );
+            p = achAddr;
+        }
+        doAddrInfo = 1;
+        break;
+
+    default:
+        pAddr->sa_family = AF_INET;
+        pEnd = strchr( p, ':' );
+        if ( !pEnd )
+            return -1;
+        *pEnd++ = 0;
+        
+        doAddrInfo = 0;
+        if ( *p == '*' )
+        {
+            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl(INADDR_ANY);
+        }
+        else if (!strcasecmp( p, "localhost" ) )
+            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = htonl( INADDR_LOOPBACK );
+        else
+        {
+            ((struct sockaddr_in *)pAddr)->sin_addr.s_addr = inet_addr( p );
+            if ( ((struct sockaddr_in *)pAddr)->sin_addr.s_addr == INADDR_BROADCAST)
+            {
+                doAddrInfo = 1;
+            }
+        }
+        break;
+    }
+    if ( *pEnd == ':' )
+        ++pEnd;
+        
+    port = atoi( pEnd );
+    if (( port <= 0 )||( port > 655535 ))
+        return -1;
+    if ( doAddrInfo )
+    {
+
+        memset(&hints, 0, sizeof(hints));
+
+        hints.ai_family   = pAddr->sa_family;
+        hints.ai_socktype = SOCK_STREAM;
+        hints.ai_protocol = IPPROTO_TCP;
+
+        if ( getaddrinfo(p, NULL, &hints, &res) )
+        {
+            return -1;
+        }
+
+        memcpy(pAddr, res->ai_addr, res->ai_addrlen);
+        freeaddrinfo(res);
+    }
+    
+    if ( pAddr->sa_family == AF_INET )
+        ((struct sockaddr_in *)pAddr)->sin_port = htons( port );
+    else
+        ((struct sockaddr_in6 *)pAddr)->sin6_port = htons( port );
+    return 0;
+    
+}
+
+int LSAPI_CreateListenSock( const char * pBind, int backlog )
+{
+    char serverAddr[128];
+    int ret;
+    int fd = -1;
+    ret = LSAPI_ParseSockAddr( pBind, (struct sockaddr *)serverAddr );
+    if ( !ret )
+    {
+        fd = LSAPI_CreateListenSock2( (struct sockaddr *)serverAddr, backlog );
+    }
+    return fd;
+}
+
+static fn_select_t g_fnSelect = select;
+
+typedef struct _lsapi_child_status
+{
+    int     m_pid;
+
+    volatile short   m_iKillSent;
+    volatile short   m_inProcess;
+
+    volatile long    m_tmWaitBegin;
+    volatile long    m_tmReqBegin;
+    volatile long    m_tmLastCheckPoint;
+}
+lsapi_child_status;
+
+static lsapi_child_status * s_pChildStatus = NULL;
+
+typedef struct _lsapi_prefork_server
+{
+    int m_fd;
+    int m_iMaxChildren;
+    int m_iExtraChildren;
+    int m_iCurChildren;
+    int m_iMaxIdleChildren;
+    int m_iServerMaxIdle;
+    int m_iChildrenMaxIdleTime;
+    int m_iMaxReqProcessTime;
+    int m_iAvoidFork;
+    
+    lsapi_child_status * m_pChildrenStatus;
+    
+}lsapi_prefork_server;
+
+static lsapi_prefork_server * g_prefork_server = NULL;
+
+int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork )
+{
+    if ( g_prefork_server )
+        return 0;
+    if ( max_children <= 1 )
+        return -1;
+    if ( max_children >= 10000)
+        max_children = 10000;
+
+    
+    g_prefork_server = (lsapi_prefork_server *)malloc( sizeof( lsapi_prefork_server ) );
+    if ( !g_prefork_server )
+        return -1;
+    memset( g_prefork_server, 0, sizeof( lsapi_prefork_server ) );
 
+    if ( fp != NULL )
+        g_fnSelect = fp;
+
+    s_ppid = getppid();
+    g_prefork_server->m_iAvoidFork = avoidFork;
+    g_prefork_server->m_iMaxChildren = max_children;
+    
+    g_prefork_server->m_iExtraChildren = ( avoidFork ) ? 0 : (max_children / 3) ;
+    g_prefork_server->m_iMaxIdleChildren = ( avoidFork ) ? (max_children + 1) : (max_children / 3);
+    g_prefork_server->m_iChildrenMaxIdleTime = 300;
+    g_prefork_server->m_iMaxReqProcessTime = 300;
+    return 0;    
+}
+
+void LSAPI_Set_Server_fd( int fd )
+{
+    if( g_prefork_server )
+        g_prefork_server->m_fd = fd;
+}
+
+
+static int lsapi_accept( int fdListen )
+{
+    int         fd;
+    int         nodelay = 1;
+    socklen_t   len;
+    char        achPeer[128];
+
+    len = sizeof( achPeer );
+    fd = accept( fdListen, (struct sockaddr *)&achPeer, &len );
+    if ( fd != -1 )
+    {
+        if (((struct sockaddr *)&achPeer)->sa_family == AF_INET )
+        {
+            setsockopt( fd, IPPROTO_TCP, TCP_NODELAY,
+                    (char *)&nodelay, sizeof(nodelay));
+        }
+    }
+    return fd;
+
+}
+
+
+
+
+static int s_req_processed = 0;
+static int s_max_reqs = 10000;
+static int s_max_idle_secs = 300;
+
+static int s_stop;
+
+static void lsapi_cleanup(int signal)
+{
+    s_stop = signal;
+}
+
+static lsapi_child_status * find_child_status( int pid )
+{
+    lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
+    lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2;
+    while( pStatus < pEnd )
+    {
+        if ( pStatus->m_pid == pid )
+            return pStatus;
+        ++pStatus;
+    }
+    return NULL;
+}
+
+
+
+static void lsapi_sigchild( int signal )
+{
+    int status, pid;
+    lsapi_child_status * child_status;
+    while( 1 )
+    {
+        pid = waitpid( -1, &status, WNOHANG|WUNTRACED );
+        if ( pid <= 0 )
+        {
+            break;
+        }
+        child_status = find_child_status( pid );
+        if ( child_status )
+            child_status->m_pid = 0;
+        --g_prefork_server->m_iCurChildren;
+    }
+
+}
+
+static int lsapi_init_children_status()
+{
+    int size = 4096;
+    
+    char * pBuf;
+    size = g_prefork_server->m_iMaxChildren * sizeof( lsapi_child_status ) * 2;
+    size = (size + 4095 ) / 4096 * 4096;
+    pBuf =( char*) mmap( NULL, size, PROT_READ | PROT_WRITE,
+        MAP_ANON | MAP_SHARED, -1, 0 );
+    if ( pBuf == MAP_FAILED )
+    {
+        perror( "Anonymous mmap() failed" );
+        return -1;
+    }
+    memset( pBuf, 0, size );
+    g_prefork_server->m_pChildrenStatus = (lsapi_child_status *)pBuf;  
+    return 0;
+}
+
+static void lsapi_check_child_status( long tmCur )
+{
+    int idle = 0;
+    int tobekilled;
+    int dying = 0;
+    lsapi_child_status * pStatus = g_prefork_server->m_pChildrenStatus;
+    lsapi_child_status * pEnd = g_prefork_server->m_pChildrenStatus + g_prefork_server->m_iMaxChildren * 2;
+    while( pStatus < pEnd )
+    {
+        tobekilled = pStatus->m_iKillSent;
+        if ( pStatus->m_pid != 0 )
+        {
+            if ( !tobekilled )
+            {
+                if ( !pStatus->m_inProcess )
+                {
+                    
+                    if (( g_prefork_server->m_iCurChildren - dying > g_prefork_server->m_iMaxChildren)||
+                        ( idle >= g_prefork_server->m_iMaxIdleChildren ))
+                    {
+                        tobekilled = 1;
+                    }
+                    else
+                    {
+                        if (( s_max_idle_secs> 0)&&(tmCur - pStatus->m_tmWaitBegin > s_max_idle_secs + 5 ))
+                            tobekilled = 1;
+                    }
+                    if ( !tobekilled )
+                        ++idle;
+                }
+                else
+                {
+                    if ( tmCur - pStatus->m_tmReqBegin > 
+                            g_prefork_server->m_iMaxReqProcessTime )
+                        tobekilled = 1;
+                }
+            }
+            else
+            {
+                if ( pStatus->m_inProcess )
+                    tobekilled = pStatus->m_iKillSent = 0;
+            }
+            if ( tobekilled )
+            {
+                tobekilled = 0;
+                if ( pStatus->m_iKillSent > 5 )
+                    tobekilled = SIGKILL;
+                else if ( pStatus->m_iKillSent == 3 )
+                    tobekilled = SIGTERM;
+                else if ( pStatus->m_iKillSent == 1 )
+                {
+                    tobekilled = SIGUSR1;
+                }
+                if ( tobekilled )
+                    kill( pStatus->m_pid, tobekilled );
+                ++pStatus->m_iKillSent;
+                ++dying;
+            }
+                
+        }
+        else
+            ++dying;
+        ++pStatus;
+    }
+}
+
+static int lsapi_all_children_must_die()
+{
+    int maxWait;
+    int sec =0;
+    g_prefork_server->m_iMaxReqProcessTime = 10;
+    g_prefork_server->m_iMaxIdleChildren = -1;
+    maxWait = 15;
+
+    while( g_prefork_server->m_iCurChildren && (sec < maxWait) )
+    {
+        lsapi_check_child_status(time(NULL));
+        sleep( 1 );
+        sec++;
+    }
+    if ( g_prefork_server->m_iCurChildren != 0 )
+        kill( -getpgrp(), SIGKILL );
+    return 0;
+}
+
+
+
+static int lsapi_prefork_server_accept( lsapi_prefork_server * pServer, LSAPI_Request * pReq )
+{
+    struct sigaction act, old_term, old_quit, old_int,
+                    old_usr1, old_child;
+    lsapi_child_status * child_status;
+    int             wait_secs = 0;
+    int             ret = 0;
+    int             pid;
+    time_t          lastTime = 0;
+    time_t          curTime = 0;
+    fd_set          readfds;
+    struct timeval  timeout;
+
+    lsapi_init_children_status();
+    
+    setsid();
+
+    act.sa_flags = 0;
+    act.sa_handler = lsapi_sigchild;
+    if( sigaction( SIGCHLD, &act, &old_child ) )
+    {
+        perror( "Can't set signal handler for SIGCHILD" );
+        return -1;
+    }
+
+    /* Set up handler to kill children upon exit */
+    act.sa_flags = 0;
+    act.sa_handler = lsapi_cleanup;
+    if( sigaction( SIGTERM, &act, &old_term ) ||
+        sigaction( SIGINT,  &act, &old_int  ) ||
+        sigaction( SIGUSR1, &act, &old_usr1 ) ||
+        sigaction( SIGQUIT, &act, &old_quit ))
+    {
+        perror( "Can't set signals" );
+        return -1;
+    }
+    s_stop = 0;
+    while( !s_stop )
+    {
+        if ( ret )
+            curTime = time( NULL );
+        else
+            ++curTime;
+        if (curTime != lastTime )
+        {
+            lastTime = curTime;
+            if (s_ppid && (getppid() != s_ppid ))
+                break;
+            lsapi_check_child_status(curTime );
+            if (pServer->m_iServerMaxIdle)
+            {
+                if ( pServer->m_iCurChildren <= 0 )
+                {
+                    ++wait_secs;
+                    if ( wait_secs > pServer->m_iServerMaxIdle )
+                        return -1;
+                }
+                else
+                    wait_secs = 0;
+            }
+        }
+
+        if ( pServer->m_iCurChildren >= (pServer->m_iMaxChildren + pServer->m_iExtraChildren ) )
+        {
+            usleep( 100000 );
+            continue;
+        }
+
+        FD_ZERO( &readfds );
+        FD_SET( pServer->m_fd, &readfds );
+        timeout.tv_sec = 1; timeout.tv_usec = 0;
+        if ((ret = (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout)) == 1 )
+        {
+            if ( pServer->m_iCurChildren >= 0 )
+            {
+                usleep( 10 );
+                FD_ZERO( &readfds );
+                FD_SET( pServer->m_fd, &readfds );
+                timeout.tv_sec = 0; timeout.tv_usec = 0;
+                if ( (*g_fnSelect)(pServer->m_fd+1, &readfds, NULL, NULL, &timeout) == 0 )
+                    continue;
+            }
+        }
+        else if ( ret == -1 )
+        {
+            if ( errno == EINTR )
+                continue;
+            /* perror( "select()" ); */
+            break;
+        }
+        else
+        {
+            continue;
+        }
+
+        pReq->m_fd = lsapi_accept( pServer->m_fd );
+        if ( pReq->m_fd != -1 )
+        {
+            child_status = find_child_status( 0 );
+            pid = fork();
+            if ( !pid )
+            {
+                g_prefork_server = NULL;
+                s_ppid = getppid();
+                s_req_processed = 0;
+                s_pChildStatus = child_status;
+                child_status->m_iKillSent = 0;
+
+                /* don't catch our signals */
+                sigaction( SIGCHLD, &old_child, 0 );
+                sigaction( SIGTERM, &old_term, 0 );
+                sigaction( SIGQUIT, &old_quit, 0 );
+                sigaction( SIGINT,  &old_int,  0 );
+                sigaction( SIGUSR1, &old_usr1, 0 );
+                return 0;
+            }
+            else if ( pid == -1 )
+            {
+                perror( "fork() failed, please increase process limit" );
+            }
+            else
+            {
+                ++pServer->m_iCurChildren;
+                if ( child_status )
+                {
+                    child_status->m_pid = pid;
+                    child_status->m_iKillSent = 0;
+                    child_status->m_tmWaitBegin = time(NULL);
+                }
+            }
+            close( pReq->m_fd );
+            pReq->m_fd = -1;
+
+        }
+        else
+        {
+            if (( errno == EINTR )||( errno == EAGAIN))
+                continue;
+            perror( "accept() failed" );
+            return -1;
+        }
+    }
+    sigaction( SIGUSR1, &old_usr1, 0 );
+    kill( -getpgrp(), SIGUSR1 );
+    lsapi_all_children_must_die();  /* Sorry, children ;-) */
+    return -1;
+
+}
+
+int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq )
+{
+    int             fd;
+    int             ret;
+    int             wait_secs;
+    fd_set          readfds;
+    struct timeval  timeout;
+
+    LSAPI_Finish_r( pReq );
+
+
+    if ( g_prefork_server )
+    {
+        if ( g_prefork_server->m_fd != -1 )
+            if ( lsapi_prefork_server_accept( g_prefork_server, pReq ) == -1 )
+                return -1;
+    }
+    if ( s_req_processed >= s_max_reqs )
+        return -1;
+
+    if ( s_pChildStatus )
+    {
+        s_pChildStatus->m_tmWaitBegin = time( NULL );
+    }
+    
+    while( g_running )
+    {
+        if ( pReq->m_fd != -1 )
+        {
+            fd = pReq->m_fd;
+        }
+        else if ( pReq->m_fdListen != -1 )
+            fd = pReq->m_fdListen;
+        else
+            return -1;
+        wait_secs = 0;
+        while( 1 )
+        {
+            if ( !g_running )
+                return -1;
+            if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
+                return -1; 
+            FD_ZERO( &readfds );
+            FD_SET( fd, &readfds );
+            timeout.tv_sec = 1;
+            timeout.tv_usec = 0;
+            ret = (*g_fnSelect)(fd+1, &readfds, NULL, NULL, &timeout);
+            if ( ret == 0 )
+            {
+                if ( s_pChildStatus )
+                {
+                    s_pChildStatus->m_inProcess = 0;
+                }
+                ++wait_secs;
+                if (( s_max_idle_secs > 0 )&&(wait_secs >= s_max_idle_secs ))
+                    return -1;
+                if ( s_ppid &&( getppid() != s_ppid))
+                    return -1;
+            }
+            else if ( ret == -1 )
+            {
+                if ( errno == EINTR )
+                    continue;
+                else
+                    return -1;
+            }
+            else if ( ret >= 1 )
+            {
+                if (( s_pChildStatus )&&( s_pChildStatus->m_iKillSent ))
+                    return -1; 
+                if ( fd == pReq->m_fdListen )
+                {
+                    pReq->m_fd = lsapi_accept( pReq->m_fdListen );
+                    if ( pReq->m_fd != -1 )
+                    {
+                        fd = pReq->m_fd;
+                    }
+                    else
+                        return -1;
+                }
+                else
+                    break;
+            }
+        }
+
+        if ( !readReq( pReq ) )
+        {
+            if ( s_pChildStatus )
+            {
+                s_pChildStatus->m_inProcess = 1;
+                s_pChildStatus->m_tmReqBegin = s_pChildStatus->m_tmLastCheckPoint = time(NULL);
+            }
+            ++s_req_processed;
+            return 0;
+        }
+        lsapi_close( pReq->m_fd );
+        pReq->m_fd = -1;
+        LSAPI_Reset_r( pReq );
+    }
+    return -1;
+    
+}
+
+void LSAPI_Set_Max_Reqs( int reqs )
+{   s_max_reqs = reqs;          }
+
+void LSAPI_Set_Max_Idle( int secs )
+{   s_max_idle_secs = secs;     }
+
+void LSAPI_Set_Max_Children( int maxChildren )
+{
+    if ( g_prefork_server )
+        g_prefork_server->m_iMaxChildren = maxChildren;
+}
+
+void LSAPI_Set_Extra_Children( int extraChildren )
+{
+    if (( g_prefork_server )&&( extraChildren >= 0 ))
+        g_prefork_server->m_iExtraChildren = extraChildren;
+}
+
+void LSAPI_Set_Max_Process_Time( int secs )
+{
+    if (( g_prefork_server )&&( secs > 0 ))
+        g_prefork_server->m_iMaxReqProcessTime = secs;
+}
+
+
+void LSAPI_Set_Max_Idle_Children( int maxIdleChld )
+{
+    if (( g_prefork_server )&&( maxIdleChld > 0 ))
+        g_prefork_server->m_iMaxIdleChildren = maxIdleChld;
+}
+
+void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle )
+{
+    if ( g_prefork_server )
+        g_prefork_server->m_iServerMaxIdle = serverMaxIdle;
+}
+
+
+void LSAPI_No_Check_ppid()
+{
+    s_ppid = 0;
+}
+
+#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+#include <crt_externs.h>
+#else
+extern char ** environ;
+#endif
+static void unset_lsapi_envs()
+{
+    char **env;
+#if defined(macintosh) || defined(__APPLE__) || defined(__APPLE_CC__)
+    env = *_NSGetEnviron();
+#else
+    env = environ;
+#endif
+    while( env != NULL && *env != NULL ) 
+    {
+        if (!strncmp(*env, "LSAPI_", 6) || !strncmp( *env, "PHP_LSAPI_", 10 ) ) 
+        {   
+            char ** del = env;
+            do 
+                *del = del[1];
+            while( *del++ );
+        }
+        else
+            ++env;
+    }  
+}
+
+void LSAPI_Init_Env_Parameters( fn_select_t fp )
+{
+    const char *p;
+    int n;
+    int avoidFork = 0;
+    p = getenv( "PHP_LSAPI_MAX_REQUESTS" );
+    if ( !p )
+        p = getenv( "LSAPI_MAX_REQS" );
+    if ( p )
+    {
+        n = atoi( p );
+        if ( n > 0 )
+            LSAPI_Set_Max_Reqs( n );
+    }
+
+    p = getenv( "LSAPI_AVOID_FORK" );
+    if ( p )
+    {
+        avoidFork = atoi( p );
+    }    
+    
+    p = getenv( "LSAPI_MAX_IDLE" );
+    if ( p )
+    {
+        n = atoi( p );
+        LSAPI_Set_Max_Idle( n );
+    }
+
+    if ( LSAPI_Is_Listen() )
+    {
+        n = 0;
+        p = getenv( "PHP_LSAPI_CHILDREN" );
+        if ( !p )
+            p = getenv( "LSAPI_CHILDREN" );
+        if ( p )
+            n = atoi( p );
+        if ( n > 1 )
+        {
+            LSAPI_Init_Prefork_Server( n, fp, avoidFork );
+            LSAPI_Set_Server_fd( g_req.m_fdListen );
+        }
+
+        p = getenv( "LSAPI_EXTRA_CHILDREN" );
+        if ( p )
+            LSAPI_Set_Extra_Children( atoi( p ) );
+        
+        p = getenv( "LSAPI_MAX_IDLE_CHILDREN" );
+        if ( p )
+            LSAPI_Set_Max_Idle_Children( atoi( p ) );
+        
+        p = getenv( "LSAPI_PGRP_MAX_IDLE" );
+        if ( p )
+        {
+            LSAPI_Set_Server_Max_Idle_Secs( atoi( p ) );
+        }
+        
+        p = getenv( "LSAPI_MAX_PROCESS_TIME" );
+        if ( p )       
+            LSAPI_Set_Max_Process_Time( atoi( p ) );
+        
+        if ( getenv( "LSAPI_PPID_NO_CHECK" ) )
+        {
+            LSAPI_No_Check_ppid();
+        }
+    }
+    unset_lsapi_envs();
+}
 
 
index e1c156fa514b600c443396e98a9d7bc8176d9217..10d3638b4862081a3f8faf32db28274fc278fb80 100644 (file)
@@ -49,6 +49,9 @@ extern "C" {
 #include <stddef.h>
 #include <lsapidef.h>
 
+#include <sys/time.h>
+#include <sys/types.h>
+
 struct LSAPI_key_value_pair
 {
     char * pKey;
@@ -64,7 +67,10 @@ typedef struct lsapi_request
 {
     int               m_fdListen;
     int               m_fd;
-    
+
+    long              m_lLastActive;
+    long              m_lReqBegin;
+
     char            * m_pReqBuf;
     int               m_reqBufSize;
     
@@ -114,14 +120,14 @@ typedef struct lsapi_request
 extern LSAPI_Request g_req;
 
 
-//return: >0 continue, ==0 stop, -1 failed
+/* return: >0 continue, ==0 stop, -1 failed  */
 typedef int (*LSAPI_CB_EnvHandler )( const char * pKey, int keyLen,
                 const char * pValue, int valLen, void * arg );
 
 
 int LSAPI_Init(void);
 
-void LSAPI_stop(void);
+void LSAPI_Stop(void);
 
 int LSAPI_Is_Listen_r( LSAPI_Request * pReq);
 
@@ -140,6 +146,9 @@ char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex );
 int LSAPI_ForeachHeader_r( LSAPI_Request * pReq,
             LSAPI_CB_EnvHandler fn, void * arg );
 
+int LSAPI_ForeachOrgHeader_r( LSAPI_Request * pReq,
+            LSAPI_CB_EnvHandler fn, void * arg );
+
 int LSAPI_ForeachEnv_r( LSAPI_Request * pReq,
             LSAPI_CB_EnvHandler fn, void * arg );
 
@@ -149,10 +158,13 @@ int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
 char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name );
             
 
-int LSAPI_GetContentLen_r( LSAPI_Request * pReq );
-
 int LSAPI_ReadReqBody_r( LSAPI_Request * pReq, char * pBuf, int len );
 
+int LSAPI_ReqBodyGetChar_r( LSAPI_Request * pReq );
+
+int LSAPI_ReqBodyGetLine_r( LSAPI_Request * pReq, char * pBuf, int bufLen, int *getLF );
+
+
 int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq );
 
 int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len );
@@ -211,6 +223,13 @@ static inline int  LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq )
     return -1;
 }
 
+static inline int LSAPI_GetReqBodyRemain_r( LSAPI_Request * pReq )
+{
+    if ( pReq )
+        return pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
+    return -1;
+}
+
 
 int LSAPI_Is_Listen(void);
 
@@ -226,6 +245,10 @@ static inline char * LSAPI_GetHeader( int headerIndex )
 static inline int LSAPI_ForeachHeader( LSAPI_CB_EnvHandler fn, void * arg )
 {   return LSAPI_ForeachHeader_r( &g_req, fn, arg );        }
 
+static inline int LSAPI_ForeachOrgHeader(
+            LSAPI_CB_EnvHandler fn, void * arg )
+{   return LSAPI_ForeachOrgHeader_r( &g_req, fn, arg );     }
+
 static inline int LSAPI_ForeachEnv( LSAPI_CB_EnvHandler fn, void * arg )
 {   return LSAPI_ForeachEnv_r( &g_req, fn, arg );           }
 
@@ -250,9 +273,20 @@ static inline char * LSAPI_GetRequestMethod()
 static inline int LSAPI_GetReqBodyLen()
 {   return LSAPI_GetReqBodyLen_r( &g_req );                 }
 
+static inline int LSAPI_GetReqBodyRemain()
+{   return LSAPI_GetReqBodyRemain_r( &g_req );                 }
+
 static inline int LSAPI_ReadReqBody( char * pBuf, int len )
 {   return LSAPI_ReadReqBody_r( &g_req, pBuf, len );        }
 
+static inline int LSAPI_ReqBodyGetChar()
+{   return LSAPI_ReqBodyGetChar_r( &g_req );        }
+
+static inline int LSAPI_ReqBodyGetLine( char * pBuf, int len, int *getLF )
+{   return LSAPI_ReqBodyGetLine_r( &g_req, pBuf, len, getLF );        }
+
+
+
 static inline int LSAPI_FinalizeRespHeaders(void)
 {   return LSAPI_FinalizeRespHeaders_r( &g_req );           }
 
@@ -271,6 +305,31 @@ static inline int LSAPI_AppendRespHeader( char * pBuf, int len )
 static inline int LSAPI_SetRespStatus( int code )
 {   return LSAPI_SetRespStatus_r( &g_req, code );           }
 
+int LSAPI_IsRunning(void);
+
+int LSAPI_CreateListenSock( const char * pBind, int backlog );
+
+typedef int (*fn_select_t)( int, fd_set *, fd_set *, fd_set *, struct timeval * );
+
+int LSAPI_Init_Prefork_Server( int max_children, fn_select_t fp, int avoidFork );
+
+void LSAPI_Set_Server_fd( int fd );
+
+int LSAPI_Prefork_Accept_r( LSAPI_Request * pReq );
+
+void LSAPI_Set_Max_Reqs( int reqs );
+
+void LSAPI_Set_Max_Idle( int secs );
+
+void LSAPI_Set_Max_Children( int maxChildren );
+
+void LSAPI_Set_Max_Idle_Children( int maxIdleChld );
+
+void LSAPI_Set_Server_Max_Idle_Secs( int serverMaxIdle );
+
+void LSAPI_Set_Max_Process_Time( int secs );
+
+void LSAPI_Init_Env_Parameters( fn_select_t fp );
 
 #if defined (c_plusplus) || defined (__cplusplus)
 }