summaryrefslogtreecommitdiff
path: root/sapi/litespeed
diff options
context:
space:
mode:
Diffstat (limited to 'sapi/litespeed')
-rw-r--r--sapi/litespeed/CREDITS2
-rw-r--r--sapi/litespeed/Makefile.frag9
-rw-r--r--sapi/litespeed/README225
-rw-r--r--sapi/litespeed/config.m431
-rw-r--r--sapi/litespeed/lsapi_main.c1118
-rw-r--r--sapi/litespeed/lsapidef.h196
-rw-r--r--sapi/litespeed/lsapilib.c2227
-rw-r--r--sapi/litespeed/lsapilib.h363
8 files changed, 4171 insertions, 0 deletions
diff --git a/sapi/litespeed/CREDITS b/sapi/litespeed/CREDITS
new file mode 100644
index 0000000..2fa192e
--- /dev/null
+++ b/sapi/litespeed/CREDITS
@@ -0,0 +1,2 @@
+litespeed
+George Wang
diff --git a/sapi/litespeed/Makefile.frag b/sapi/litespeed/Makefile.frag
new file mode 100644
index 0000000..b70e5e8
--- /dev/null
+++ b/sapi/litespeed/Makefile.frag
@@ -0,0 +1,9 @@
+litespeed: $(SAPI_LITESPEED_PATH)
+
+$(SAPI_LITESPEED_PATH): $(PHP_GLOBAL_OBJS) $(PHP_BINARY_OBJS) $(PHP_LITESPEED_OBJS)
+ $(BUILD_LITESPEED)
+
+install-litespeed: $(SAPI_LITESPEED_PATH)
+ @echo "Installing PHP LitSpeed binary: $(INSTALL_ROOT)$(bindir)/"
+ @$(INSTALL) -m 0755 $(SAPI_LITESPEED_PATH) $(INSTALL_ROOT)$(bindir)/lsphp
+
diff --git a/sapi/litespeed/README b/sapi/litespeed/README
new file mode 100644
index 0000000..e548ec9
--- /dev/null
+++ b/sapi/litespeed/README
@@ -0,0 +1,225 @@
+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 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 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 same configuration directives.
+
+PHP with LiteSpeed SAPI is highly recommended over FastCGI PHP for
+PHP scripting with LiteSpeed web server.
+
+
+Building PHP with LiteSpeed SAPI
+================================
+
+You need to add "--with-litespeed" to the configure command to build
+PHP with LiteSpeed SAPI, all other SAPI related configure options
+should be removed.
+
+For example:
+ ./configure --with-litespeed
+ make
+
+You should find an executable called 'php' under sapi/litespeed/
+directory after the compilation succeeds. Copy it to
+'lsws/fcgi-bin/lsphp' or wherever you prefer, if LiteSpeed web server
+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
+=============================================
+
+Detailed information about how to configure LiteSpeed web server with
+PHP support is available from our website, at:
+
+http://www.litespeedtech.com/docs/HowTo_QA.html
+
+Usually, PHP support has been configured out of box, you don't need to
+change it unless you want to change PHP interface from FastCGI to
+LiteSpeed SAPI or vice versa.
+
+Brief instructions are as follow:
+
+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
+ API', 'Handler Name' should be the name of external application
+ just defined.
+
+
+3) Click 'Apply Changes' link on the top left of the page, then click
+ 'graceful restart'. Now PHP is running with LiteSpeed SAPI.
+
+Tunings
+-------
+
+There are a few environment variables that can be tweaked to control the
+behavior of LSAPI application.
+
+* LSAPI_CHILDREN or PHP_LSAPI_CHILDREN (default: 0)
+
+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.
+
+Self Managed Mode is preferred because all PHP processes can share one
+shared memory block for the opcode cache.
+
+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
+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
+=======
+
+For support questions, please post to our free support forum, at:
+
+http://www.litespeedtech.com/forum/
+
+For bug report, please send bug report to bug [at] litespeedtech.com.
+
+
+
+
diff --git a/sapi/litespeed/config.m4 b/sapi/litespeed/config.m4
new file mode 100644
index 0000000..268b9ae
--- /dev/null
+++ b/sapi/litespeed/config.m4
@@ -0,0 +1,31 @@
+dnl
+dnl $Id$
+dnl
+
+AC_MSG_CHECKING(for LiteSpeed support)
+
+PHP_ARG_WITH(litespeed,,
+[ --with-litespeed Build PHP as litespeed module], no)
+
+if test "$PHP_LITESPEED" != "no"; then
+ PHP_ADD_MAKEFILE_FRAGMENT($abs_srcdir/sapi/litespeed/Makefile.frag,$abs_srcdir/sapi/litespeed,sapi/litespeed)
+ SAPI_LITESPEED_PATH=sapi/litespeed/php
+ PHP_SELECT_SAPI(litespeed, program, lsapi_main.c lsapilib.c, "", '$(SAPI_LITESPEED_PATH)')
+ case $host_alias in
+ *darwin*)
+ BUILD_LITESPEED="\$(CC) \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(NATIVE_RPATHS) \$(PHP_GLOBAL_OBJS:.lo=.o) \$(PHP_BINARY_OBJS:.lo=.o) \$(PHP_LITESPEED_OBJS:.lo=.o) \$(PHP_FRAMEWORKS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_LITESPEED_PATH)"
+ ;;
+ *cygwin*)
+ SAPI_LITESPEED_PATH=sapi/litespeed/php.exe
+ BUILD_LITESPEED="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_BINARY_OBJS) \$(PHP_LITESPEED_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_LITESPEED_PATH)"
+ ;;
+ *)
+ BUILD_LITESPEED="\$(LIBTOOL) --mode=link \$(CC) -export-dynamic \$(CFLAGS_CLEAN) \$(EXTRA_CFLAGS) \$(EXTRA_LDFLAGS_PROGRAM) \$(LDFLAGS) \$(PHP_RPATHS) \$(PHP_GLOBAL_OBJS) \$(PHP_BINARY_OBJS) \$(PHP_LITESPEED_OBJS) \$(EXTRA_LIBS) \$(ZEND_EXTRA_LIBS) -o \$(SAPI_LITESPEED_PATH)"
+ ;;
+ esac
+
+ PHP_SUBST(SAPI_LITESPEED_PATH)
+ PHP_SUBST(BUILD_LITESPEED)
+fi
+
+AC_MSG_RESULT($PHP_LITESPEED)
diff --git a/sapi/litespeed/lsapi_main.c b/sapi/litespeed/lsapi_main.c
new file mode 100644
index 0000000..f33b049
--- /dev/null
+++ b/sapi/litespeed/lsapi_main.c
@@ -0,0 +1,1118 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: George Wang <gwang@litespeedtech.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "SAPI.h"
+#include "php_main.h"
+#include "php_ini.h"
+#include "php_variables.h"
+#include "zend_highlight.h"
+#include "zend.h"
+
+#include "lsapilib.h"
+
+#include <stdio.h>
+
+#if HAVE_STDLIB_H
+#include <stdlib.h>
+#endif
+
+#if HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#ifdef PHP_WIN32
+
+#include <io.h>
+#include <fcntl.h>
+#include "win32/php_registry.h"
+
+#else
+
+#include <sys/wait.h>
+
+#endif
+
+#include <sys/stat.h>
+
+#if HAVE_SYS_TYPES_H
+
+#include <sys/types.h>
+
+#endif
+
+#if HAVE_SIGNAL_H
+
+#include <signal.h>
+
+#endif
+
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <netinet/in.h>
+
+
+#define SAPI_LSAPI_MAX_HEADER_LENGTH 2048
+
+static int lsapi_mode = 1;
+static char *php_self = "";
+static char *script_filename = "";
+static int source_highlight = 0;
+static char * argv0 = NULL;
+static int engine = 1;
+#ifdef ZTS
+zend_compiler_globals *compiler_globals;
+zend_executor_globals *executor_globals;
+php_core_globals *core_globals;
+sapi_globals_struct *sapi_globals;
+void ***tsrm_ls;
+#endif
+
+zend_module_entry litespeed_module_entry;
+
+/* {{{ php_lsapi_startup
+ */
+static int php_lsapi_startup(sapi_module_struct *sapi_module)
+{
+ if (php_module_startup(sapi_module, NULL, 0)==FAILURE) {
+ return FAILURE;
+ }
+ argv0 = sapi_module->executable_location;
+ return SUCCESS;
+}
+/* }}} */
+
+/* {{{ sapi_lsapi_ini_defaults */
+
+/* overwriteable ini defaults must be set in sapi_cli_ini_defaults() */
+#define INI_DEFAULT(name,value)\
+ ZVAL_STRING(tmp, value, 0);\
+ zend_hash_update(configuration_hash, name, sizeof(name), tmp, sizeof(zval), (void**)&entry);\
+ Z_STRVAL_P(entry) = zend_strndup(Z_STRVAL_P(entry), Z_STRLEN_P(entry))
+
+static void sapi_lsapi_ini_defaults(HashTable *configuration_hash)
+{
+ zval *tmp, *entry;
+
+#if PHP_MAJOR_VERSION > 4
+/*
+ MAKE_STD_ZVAL(tmp);
+
+ INI_DEFAULT("register_long_arrays", "0");
+
+ FREE_ZVAL(tmp);
+*/
+#endif
+
+}
+/* }}} */
+
+
+/* {{{ sapi_lsapi_ub_write
+ */
+static int sapi_lsapi_ub_write(const char *str, uint str_length TSRMLS_DC)
+{
+ int ret;
+ int remain;
+ if ( lsapi_mode ) {
+ ret = LSAPI_Write( str, str_length );
+ if ( ret < str_length ) {
+ php_handle_aborted_connection();
+ return str_length - ret;
+ }
+ } else {
+ remain = str_length;
+ while( remain > 0 ) {
+ ret = write( 1, str, remain );
+ if ( ret <= 0 ) {
+ php_handle_aborted_connection();
+ return str_length - remain;
+ }
+ str += ret;
+ remain -= ret;
+ }
+ }
+ return str_length;
+}
+/* }}} */
+
+
+/* {{{ sapi_lsapi_flush
+ */
+static void sapi_lsapi_flush( void * server_context )
+{
+ if ( lsapi_mode ) {
+ if ( LSAPI_Flush() == -1) {
+ php_handle_aborted_connection();
+ }
+ }
+}
+/* }}} */
+
+
+/* {{{ sapi_lsapi_deactivate
+ */
+static int sapi_lsapi_deactivate(TSRMLS_D)
+{
+ if ( SG(request_info).path_translated )
+ {
+ efree( SG(request_info).path_translated );
+ }
+
+ return SUCCESS;
+}
+/* }}} */
+
+
+
+
+/* {{{ sapi_lsapi_getenv
+ */
+static char *sapi_lsapi_getenv( char * name, size_t name_len TSRMLS_DC )
+{
+ if ( lsapi_mode ) {
+ return LSAPI_GetEnv( name );
+ } else {
+ return getenv( name );
+ }
+}
+/* }}} */
+
+
+/*
+static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen,
+ void * arg )
+{
+ php_register_variable_safe((char *)pKey, (char *)pValue, valLen, (zval *)arg TSRMLS_CC);
+ return 1;
+}
+*/
+
+static int add_variable( const char * pKey, int keyLen, const char * pValue, int valLen,
+ void * arg )
+{
+ zval * gpc_element, **gpc_element_p;
+ HashTable * symtable1 = Z_ARRVAL_P((zval * )arg);
+ register char * pKey1 = (char *)pKey;
+
+ MAKE_STD_ZVAL(gpc_element);
+ Z_STRLEN_P( gpc_element ) = valLen;
+ Z_STRVAL_P( gpc_element ) = estrndup(pValue, valLen);
+ Z_TYPE_P( gpc_element ) = IS_STRING;
+#if PHP_MAJOR_VERSION > 4
+ zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#else
+ zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#endif
+ return 1;
+}
+
+
+#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
+static int add_variable_magic_quote( const char * pKey, int keyLen, const char * pValue, int valLen,
+ void * arg )
+{
+ zval * gpc_element, **gpc_element_p;
+ HashTable * symtable1 = Z_ARRVAL_P((zval * )arg);
+ register char * pKey1 = (char *)pKey;
+
+ MAKE_STD_ZVAL(gpc_element);
+ Z_STRLEN_P( gpc_element ) = valLen;
+ Z_STRVAL_P( gpc_element ) = php_addslashes((char *)pValue, valLen, &Z_STRLEN_P( gpc_element ), 0 );
+ Z_TYPE_P( gpc_element ) = IS_STRING;
+#if PHP_MAJOR_VERSION > 4
+ zend_symtable_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#else
+ zend_hash_update( symtable1, pKey1, keyLen + 1, &gpc_element, sizeof( zval *), (void **) &gpc_element_p );
+#endif
+ return 1;
+}
+
+#endif
+
+/* {{{ sapi_lsapi_register_variables
+ */
+static void sapi_lsapi_register_variables(zval *track_vars_array TSRMLS_DC)
+{
+ char * php_self = "";
+ if ( lsapi_mode ) {
+ if ( (SG(request_info).request_uri ) )
+ php_self = (SG(request_info).request_uri );
+
+#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
+ if (!PG(magic_quotes_gpc)) {
+#endif
+ LSAPI_ForeachHeader( add_variable, track_vars_array );
+ LSAPI_ForeachEnv( add_variable, track_vars_array );
+ add_variable("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array );
+#if ((PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 4) || PHP_MAJOR_VERSION < 5)
+ } else {
+ LSAPI_ForeachHeader( add_variable_magic_quote, track_vars_array );
+ LSAPI_ForeachEnv( add_variable_magic_quote, track_vars_array );
+ add_variable_magic_quote("PHP_SELF", 8, php_self, strlen( php_self ), track_vars_array );
+ }
+#endif
+ php_import_environment_variables(track_vars_array TSRMLS_CC);
+ } else {
+ php_import_environment_variables(track_vars_array TSRMLS_CC);
+
+ php_register_variable("PHP_SELF", php_self, track_vars_array TSRMLS_CC);
+ php_register_variable("SCRIPT_NAME", php_self, track_vars_array TSRMLS_CC);
+ php_register_variable("SCRIPT_FILENAME", script_filename, track_vars_array TSRMLS_CC);
+ php_register_variable("PATH_TRANSLATED", script_filename, track_vars_array TSRMLS_CC);
+ php_register_variable("DOCUMENT_ROOT", "", track_vars_array TSRMLS_CC);
+
+ }
+}
+/* }}} */
+
+
+/* {{{ sapi_lsapi_read_post
+ */
+static int sapi_lsapi_read_post(char *buffer, uint count_bytes TSRMLS_DC)
+{
+ if ( lsapi_mode ) {
+ return LSAPI_ReadReqBody( buffer, count_bytes );
+ } else {
+ return 0;
+ }
+}
+/* }}} */
+
+
+
+
+/* {{{ sapi_lsapi_read_cookies
+ */
+static char *sapi_lsapi_read_cookies(TSRMLS_D)
+{
+ if ( lsapi_mode ) {
+ return LSAPI_GetHeader( H_COOKIE );
+ } else {
+ return NULL;
+ }
+}
+/* }}} */
+
+
+/* {{{ sapi_lsapi_send_headers
+ */
+static int sapi_lsapi_send_headers(sapi_headers_struct *sapi_headers TSRMLS_DC)
+{
+ sapi_header_struct *h;
+ zend_llist_position pos;
+ if ( lsapi_mode ) {
+ LSAPI_SetRespStatus( SG(sapi_headers).http_response_code );
+
+ h = zend_llist_get_first_ex(&sapi_headers->headers, &pos);
+ while (h) {
+ 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( headerBuf, SAPI_LSAPI_MAX_HEADER_LENGTH - 1,
+ "Content-type: %s", hd );
+ efree(hd);
+
+ LSAPI_AppendRespHeader( headerBuf, len );
+ }
+ }
+ LSAPI_FinalizeRespHeaders();
+ return SAPI_HEADER_SENT_SUCCESSFULLY;
+
+
+}
+/* }}} */
+
+
+/* {{{ sapi_lsapi_send_headers
+ */
+static void sapi_lsapi_log_message(char *message TSRMLS_DC)
+{
+ int len = strlen( message );
+ LSAPI_Write_Stderr( message, len);
+}
+/* }}} */
+
+
+/* {{{ sapi_module_struct cgi_sapi_module
+ */
+static sapi_module_struct lsapi_sapi_module =
+{
+ "litespeed",
+ "LiteSpeed V5.5",
+
+ php_lsapi_startup, /* startup */
+ php_module_shutdown_wrapper, /* shutdown */
+
+ NULL, /* activate */
+ sapi_lsapi_deactivate, /* deactivate */
+
+ sapi_lsapi_ub_write, /* unbuffered write */
+ sapi_lsapi_flush, /* flush */
+ NULL, /* get uid */
+ sapi_lsapi_getenv, /* getenv */
+
+ php_error, /* error handler */
+
+ NULL, /* header handler */
+ sapi_lsapi_send_headers, /* send headers handler */
+ NULL, /* send header handler */
+
+ sapi_lsapi_read_post, /* read POST data */
+ sapi_lsapi_read_cookies, /* read Cookies */
+
+ sapi_lsapi_register_variables, /* register server variables */
+ sapi_lsapi_log_message, /* Log message */
+
+ NULL, /* php.ini path override */
+ NULL, /* block interruptions */
+ NULL, /* unblock interruptions */
+ NULL, /* default post reader */
+ NULL, /* treat data */
+ NULL, /* executable location */
+
+ 0, /* php.ini ignore */
+
+ STANDARD_SAPI_MODULE_PROPERTIES
+
+};
+/* }}} */
+
+static int init_request_info( TSRMLS_D )
+{
+ char * pContentType = LSAPI_GetHeader( H_CONTENT_TYPE );
+ char * pAuth;
+
+ SG(request_info).content_type = pContentType ? pContentType : "";
+ SG(request_info).request_method = LSAPI_GetRequestMethod();
+ SG(request_info).query_string = LSAPI_GetQueryString();
+ SG(request_info).request_uri = LSAPI_GetScriptName();
+ SG(request_info).content_length = LSAPI_GetReqBodyLen();
+ SG(request_info).path_translated = estrdup( LSAPI_GetScriptFileName());
+
+ /* 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);
+}
+
+static char s_cur_chdir[4096] = "";
+
+static int lsapi_chdir_primary_script( zend_file_handle * file_handle )
+{
+#if PHP_MAJOR_VERSION > 4
+ char * p;
+ char ch;
+
+ SG(options) |= SAPI_OPTION_NO_CHDIR;
+ getcwd( s_cur_chdir, sizeof( s_cur_chdir ) );
+
+ p = strrchr( file_handle->filename, '/' );
+ if ( *p )
+ {
+ *p = 0;
+ if ( strcmp( file_handle->filename, s_cur_chdir ) != 0 ) {
+ chdir( file_handle->filename );
+ }
+ *p++ = '/';
+ ch = *p;
+ *p = 0;
+ if ( !CWDG(cwd).cwd ||
+ ( strcmp( file_handle->filename, CWDG(cwd).cwd ) != 0 ) ) {
+ CWDG(cwd).cwd_length = p - file_handle->filename;
+ CWDG(cwd).cwd = (char *) realloc(CWDG(cwd).cwd, CWDG(cwd).cwd_length+1);
+ memmove( CWDG(cwd).cwd, file_handle->filename, CWDG(cwd).cwd_length+1 );
+ }
+ *p = ch;
+ }
+ /* virtual_file_ex(&CWDG(cwd), file_handle->filename, NULL, CWD_REALPATH); */
+#else
+ VCWD_CHDIR_FILE( file_handle->filename );
+#endif
+ return 0;
+}
+
+static int lsapi_fopen_primary_script( zend_file_handle * file_handle )
+{
+ FILE * fp;
+ char * p;
+ fp = fopen( SG(request_info).path_translated, "rb" );
+ if ( !fp )
+ {
+ return -1;
+ }
+ file_handle->type = ZEND_HANDLE_FP;
+ file_handle->handle.fp = fp;
+ file_handle->filename = SG(request_info).path_translated;
+ file_handle->free_filename = 0;
+ file_handle->opened_path = NULL;
+
+ lsapi_chdir_primary_script( file_handle );
+
+ return 0;
+}
+
+static int lsapi_execute_script( zend_file_handle * file_handle TSRMLS_DC)
+{
+ char *p;
+ int len;
+ file_handle->type = ZEND_HANDLE_FILENAME;
+ file_handle->handle.fd = 0;
+ file_handle->filename = SG(request_info).path_translated;
+ file_handle->free_filename = 0;
+ file_handle->opened_path = NULL;
+
+ p = argv0;
+ *p++ = ':';
+ len = strlen( SG(request_info).path_translated );
+ if ( len > 45 )
+ len = len - 45;
+ else
+ len = 0;
+ memccpy( p, SG(request_info).path_translated + len, 0, 46 );
+
+ php_execute_script(file_handle TSRMLS_CC);
+ return 0;
+
+}
+
+
+static int lsapi_module_main(int show_source TSRMLS_DC)
+{
+ zend_file_handle file_handle = {0};
+
+ if (php_request_startup(TSRMLS_C) == FAILURE ) {
+ return -1;
+ }
+ if (show_source) {
+ 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 {
+ lsapi_execute_script( &file_handle TSRMLS_CC);
+ }
+ zend_try {
+ php_request_shutdown(NULL);
+ *argv0 = 0;
+ } zend_end_try();
+ return 0;
+}
+
+
+static int alter_ini( const char * pKey, int keyLen, const char * pValue, int valLen,
+ void * arg )
+{
+ int type = ZEND_INI_PERDIR;
+ if ( '\001' == *pKey ) {
+ ++pKey;
+ if ( *pKey == 4 ) {
+ type = ZEND_INI_SYSTEM;
+ }
+ ++pKey;
+ --keyLen;
+ if (( keyLen == 7 )&&( strncasecmp( pKey, "engine", 6 )== 0 ))
+ {
+ if ( *pValue == '0' )
+ engine = 0;
+ }
+ else
+ zend_alter_ini_entry((char *)pKey, keyLen,
+ (char *)pValue, valLen,
+ type, PHP_INI_STAGE_ACTIVATE);
+ }
+ return 1;
+}
+
+
+static void override_ini()
+{
+
+ LSAPI_ForeachSpecialEnv( alter_ini, NULL );
+
+}
+
+static int processReq( TSRMLS_D )
+{
+ int ret = 0;
+ zend_first_try {
+ /* avoid server_context==NULL checks */
+ SG(server_context) = (void *) 1;
+
+ engine = 1;
+ override_ini();
+
+ if ( engine ) {
+ init_request_info( TSRMLS_C );
+
+ if ( lsapi_module_main( source_highlight TSRMLS_CC ) == -1 ) {
+ ret = -1;
+ }
+ } else {
+ LSAPI_AppendRespHeader( "status: 403", 11 );
+ LSAPI_AppendRespHeader( "content-type: text/html", 23 );
+ LSAPI_Write( "Forbidden: PHP engine is disable.\n", 34 );
+ }
+ } zend_end_try();
+ return ret;
+}
+
+static void cli_usage( TSRMLS_D )
+{
+ static const char * usage =
+ "Usage: php\n"
+ " 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);
+ php_printf( "%s", usage );
+#ifdef PHP_OUTPUT_NEWAPI
+ php_output_end_all(TSRMLS_C);
+#else
+ php_end_ob_buffers(1 TSRMLS_CC);
+#endif
+}
+
+static int parse_opt( int argc, char * argv[], int *climode,
+ char **php_ini_path, char ** php_bind )
+{
+ char ** p = &argv[1];
+ char ** argend= &argv[argc];
+ int c;
+ while (( p < argend )&&(**p == '-' )) {
+ c = *((*p)+1);
+ ++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 ) {
+ fprintf( stderr, "<path> or <file> must be specified following '-c' option.\n");
+
+ return -1;
+ }
+ *php_ini_path = *p++;
+ break;
+ case 's':
+ source_highlight = 1;
+ break;
+ case 'h':
+ case 'i':
+ case 'q':
+ case 'v':
+ case '?':
+ default:
+ *climode = 1;
+ break;
+ }
+ }
+ if ( p - argv < argc ) {
+ *climode = 1;
+ }
+ return 0;
+}
+
+static int cli_main( int argc, char * argv[] )
+{
+
+ static const char * ini_defaults[] = {
+ "report_zend_debug", "0",
+ "display_errors", "1",
+ "register_argc_argv", "1",
+ "html_errors", "0",
+ "implicit_flush", "1",
+ "output_buffering", "0",
+ "max_execution_time", "0",
+ "max_input_time", "-1",
+ NULL
+ };
+
+ const char ** ini;
+ char ** p = &argv[1];
+ char ** argend= &argv[argc];
+ int ret = 0;
+ int c;
+ lsapi_mode = 0; /* enter CLI mode */
+
+#ifdef PHP_WIN32
+ _fmode = _O_BINARY; /*sets default for file streams to binary */
+ setmode(_fileno(stdin), O_BINARY); /* make the stdio mode be binary */
+ setmode(_fileno(stdout), O_BINARY); /* make the stdio mode be binary */
+ setmode(_fileno(stderr), O_BINARY); /* make the stdio mode be binary */
+#endif
+
+ zend_first_try {
+ SG(server_context) = (void *) 1;
+
+ zend_uv.html_errors = 0; /* tell the engine we're in non-html mode */
+ CG(in_compilation) = 0; /* not initialized but needed for several options */
+ EG(uninitialized_zval_ptr) = NULL;
+
+ for( ini = ini_defaults; *ini; ini+=2 ) {
+ zend_alter_ini_entry( (char *)*ini, strlen( *ini )+1,
+ (char *)*(ini+1), strlen( *(ini+1) ),
+ PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
+ }
+
+ while (( p < argend )&&(**p == '-' )) {
+ c = *((*p)+1);
+ ++p;
+ switch( c ) {
+ case 'q':
+ break;
+ case 'i':
+ if (php_request_startup(TSRMLS_C) != FAILURE) {
+ php_print_info(0xFFFFFFFF TSRMLS_CC);
+#ifdef PHP_OUTPUT_NEWAPI
+ php_output_end_all(TSRMLS_C);
+#else
+ php_end_ob_buffers(1 TSRMLS_CC);
+#endif
+ php_request_shutdown( NULL );
+ }
+ ret = 1;
+ break;
+ case 'v':
+ if (php_request_startup(TSRMLS_C) != FAILURE) {
+#if ZEND_DEBUG
+ php_printf("PHP %s (%s) (built: %s %s) (DEBUG)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+#else
+ php_printf("PHP %s (%s) (built: %s %s)\nCopyright (c) 1997-2013 The PHP Group\n%s", PHP_VERSION, sapi_module.name, __DATE__, __TIME__, get_zend_version());
+#endif
+#ifdef PHP_OUTPUT_NEWAPI
+ php_output_end_all(TSRMLS_C);
+#else
+ php_end_ob_buffers(1 TSRMLS_CC);
+#endif
+ php_request_shutdown( NULL );
+ }
+ ret = 1;
+ break;
+ case 'c':
+ ++p;
+ /* fall through */
+ case 's':
+ break;
+
+ case 'h':
+ case '?':
+ default:
+ cli_usage(TSRMLS_C);
+ ret = 1;
+ break;
+
+ }
+ }
+ if ( !ret ) {
+ if ( *p ) {
+ zend_file_handle file_handle = {0};
+
+ file_handle.type = ZEND_HANDLE_FP;
+ file_handle.handle.fp = VCWD_FOPEN(*p, "rb");
+
+ if ( file_handle.handle.fp ) {
+ script_filename = *p;
+ php_self = *p;
+
+ SG(request_info).path_translated = estrdup(*p);
+ SG(request_info).argc = argc - (p - argv);
+ SG(request_info).argv = p;
+
+ if (php_request_startup(TSRMLS_C) == FAILURE ) {
+ fclose( file_handle.handle.fp );
+ ret = 2;
+ } 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);
+ }
+
+ php_request_shutdown( NULL );
+ }
+ } else {
+ php_printf("Could not open input file: %s.\n", *p);
+ }
+ } else {
+ cli_usage(TSRMLS_C);
+ }
+ }
+
+ }zend_end_try();
+
+ php_module_shutdown(TSRMLS_C);
+
+#ifdef ZTS
+ tsrm_shutdown();
+#endif
+ return ret;
+}
+
+static int s_stop;
+void litespeed_cleanup(int signal)
+{
+ s_stop = signal;
+}
+
+
+void start_children( int children )
+{
+ struct sigaction act, old_term, old_quit, old_int, old_usr1;
+ int running = 0;
+ int status;
+ pid_t pid;
+
+ /* Create a process group */
+ setsid();
+
+ /* Set up handler to kill children upon exit */
+ act.sa_flags = 0;
+ act.sa_handler = litespeed_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" );
+ exit( 1 );
+ }
+ s_stop = 0;
+ while( 1 ) {
+ while((!s_stop )&&( running < children )) {
+ pid = fork();
+ switch( pid ) {
+ case 0: /* children process */
+
+ /* don't catch our signals */
+ sigaction( SIGTERM, &old_term, 0 );
+ sigaction( SIGQUIT, &old_quit, 0 );
+ sigaction( SIGINT, &old_int, 0 );
+ sigaction( SIGUSR1, &old_usr1, 0 );
+ return ;
+ case -1:
+ perror( "php (pre-forking)" );
+ exit( 1 );
+ break;
+ default: /* parent process */
+ running++;
+ break;
+ }
+ }
+ if ( s_stop ) {
+ break;
+ }
+ pid = wait( &status );
+ running--;
+ }
+ kill( -getpgrp(), SIGUSR1 );
+ exit( 0 );
+}
+
+
+
+#include <fcntl.h>
+int main( int argc, char * argv[] )
+{
+ int ret;
+ int bindFd;
+
+ char * php_ini_path = NULL;
+ char * php_bind = NULL;
+ char * p;
+ int n;
+ int climode = 0;
+ struct timeval tv_req_begin;
+ struct timeval tv_req_end;
+ int slow_script_msec = 0;
+ char time_buf[40];
+
+#ifdef HAVE_SIGNAL_H
+#if defined(SIGPIPE) && defined(SIG_IGN)
+ signal(SIGPIPE, SIG_IGN);
+#endif
+#endif
+
+#ifdef ZTS
+ tsrm_startup(1, 1, 0, NULL);
+#endif
+
+ if (argc > 1 ) {
+ if ( parse_opt( argc, argv, &climode,
+ &php_ini_path, &php_bind ) == -1 ) {
+ return 1;
+ }
+ }
+ if ( climode ) {
+ lsapi_sapi_module.phpinfo_as_text = 1;
+ }
+ argv0 = argv[0] + strlen( argv[0] );
+ sapi_startup(&lsapi_sapi_module);
+
+#ifdef ZTS
+ compiler_globals = ts_resource(compiler_globals_id);
+ executor_globals = ts_resource(executor_globals_id);
+ core_globals = ts_resource(core_globals_id);
+ sapi_globals = ts_resource(sapi_globals_id);
+ tsrm_ls = ts_resource(0);
+
+ SG(request_info).path_translated = NULL;
+#endif
+
+ lsapi_sapi_module.executable_location = argv[0];
+
+ if ( php_ini_path ) {
+ lsapi_sapi_module.php_ini_path_override = php_ini_path;
+ }
+
+
+ lsapi_sapi_module.ini_defaults = sapi_lsapi_ini_defaults;
+
+ if (php_module_startup(&lsapi_sapi_module, &litespeed_module_entry, 1) == FAILURE) {
+#ifdef ZTS
+ tsrm_shutdown();
+#endif
+ return FAILURE;
+ }
+
+ if ( climode ) {
+ return cli_main(argc, argv);
+ }
+
+ if ( php_bind ) {
+ bindFd = LSAPI_CreateListenSock( php_bind, 10 );
+ if ( bindFd == -1 ) {
+ fprintf( stderr,
+ "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 );
+
+ slow_script_msec = LSAPI_Get_Slow_Req_Msecs();
+
+ if ( php_bind ) {
+ LSAPI_No_Check_ppid();
+ }
+
+ while( LSAPI_Prefork_Accept_r( &g_req ) >= 0 ) {
+ if ( slow_script_msec ) {
+ gettimeofday( &tv_req_begin, NULL );
+ }
+ ret = processReq(TSRMLS_C);
+ if ( slow_script_msec ) {
+ gettimeofday( &tv_req_end, NULL );
+ n = ((long) tv_req_end.tv_sec - tv_req_begin.tv_sec ) * 1000
+ + (tv_req_end.tv_usec - tv_req_begin.tv_usec) / 1000;
+ if ( n > slow_script_msec )
+ {
+ strftime( time_buf, 30, "%d/%b/%Y:%H:%M:%S", localtime( &tv_req_end.tv_sec ) );
+ fprintf( stderr, "[%s] Slow PHP script: %d ms\n URL: %s %s\n Query String: %s\n Script: %s\n",
+ time_buf, n, LSAPI_GetRequestMethod(),
+ LSAPI_GetScriptName(), LSAPI_GetQueryString(),
+ LSAPI_GetScriptFileName() );
+
+ }
+ }
+ LSAPI_Finish();
+ if ( ret ) {
+ break;
+ }
+ }
+ php_module_shutdown(TSRMLS_C);
+
+#ifdef ZTS
+ tsrm_shutdown();
+#endif
+ return ret;
+}
+
+
+/* LiteSpeed PHP module starts here */
+
+#if PHP_MAJOR_VERSION > 4
+
+/* {{{ arginfo */
+ZEND_BEGIN_ARG_INFO(arginfo_litespeed__void, 0)
+ZEND_END_ARG_INFO()
+/* }}} */
+
+#else
+#define arginfo_litespeed__void NULL
+#endif
+
+PHP_FUNCTION(litespeed_request_headers);
+PHP_FUNCTION(litespeed_response_headers);
+
+PHP_MINFO_FUNCTION(litespeed);
+
+zend_function_entry litespeed_functions[] = {
+ PHP_FE(litespeed_request_headers, arginfo_litespeed__void)
+ PHP_FE(litespeed_response_headers, arginfo_litespeed__void)
+ PHP_FALIAS(getallheaders, litespeed_request_headers, arginfo_litespeed__void)
+ PHP_FALIAS(apache_request_headers, litespeed_request_headers, arginfo_litespeed__void)
+ PHP_FALIAS(apache_response_headers, litespeed_response_headers, arginfo_litespeed__void)
+ {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);
+
+ if ( lsapi_mode )
+ 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
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
+
+
diff --git a/sapi/litespeed/lsapidef.h b/sapi/litespeed/lsapidef.h
new file mode 100644
index 0000000..c8940a9
--- /dev/null
+++ b/sapi/litespeed/lsapidef.h
@@ -0,0 +1,196 @@
+
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: George Wang <gwang@litespeedtech.com> |
+ +----------------------------------------------------------------------+
+*/
+
+
+/*
+Copyright (c) 2007, Lite Speed Technologies Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of the Lite Speed Technologies Inc nor the
+ names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS 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 COPYRIGHT
+OWNER OR 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.
+*/
+
+
+#ifndef _LSAPIDEF_H_
+#define _LSAPIDEF_H_
+
+#include <inttypes.h>
+
+#if defined (c_plusplus) || defined (__cplusplus)
+extern "C" {
+#endif
+
+enum
+{
+ H_ACCEPT = 0,
+ H_ACC_CHARSET,
+ H_ACC_ENCODING,
+ H_ACC_LANG,
+ H_AUTHORIZATION,
+ H_CONNECTION,
+ H_CONTENT_TYPE,
+ H_CONTENT_LENGTH,
+ H_COOKIE,
+ H_COOKIE2,
+ H_HOST,
+ H_PRAGMA,
+ H_REFERER,
+ H_USERAGENT,
+ H_CACHE_CTRL,
+ H_IF_MODIFIED_SINCE,
+ H_IF_MATCH,
+ H_IF_NO_MATCH,
+ H_IF_RANGE,
+ H_IF_UNMOD_SINCE,
+ H_KEEP_ALIVE,
+ H_RANGE,
+ H_X_FORWARDED_FOR,
+ H_VIA,
+ H_TRANSFER_ENCODING
+
+};
+#define LSAPI_SOCK_FILENO 0
+
+#define LSAPI_VERSION_B0 'L'
+#define LSAPI_VERSION_B1 'S'
+
+/* Values for m_flag in lsapi_packet_header */
+#define LSAPI_ENDIAN_LITTLE 0
+#define LSAPI_ENDIAN_BIG 1
+#define LSAPI_ENDIAN_BIT 1
+
+#if defined(__i386__)||defined( __x86_64 )||defined( __x86_64__ )
+#define LSAPI_ENDIAN LSAPI_ENDIAN_LITTLE
+#else
+#define LSAPI_ENDIAN LSAPI_ENDIAN_BIG
+#endif
+
+/* Values for m_type in lsapi_packet_header */
+#define LSAPI_BEGIN_REQUEST 1
+#define LSAPI_ABORT_REQUEST 2
+#define LSAPI_RESP_HEADER 3
+#define LSAPI_RESP_STREAM 4
+#define LSAPI_RESP_END 5
+#define LSAPI_STDERR_STREAM 6
+#define LSAPI_REQ_RECEIVED 7
+
+
+#define LSAPI_MAX_HEADER_LEN 65535
+#define LSAPI_MAX_DATA_PACKET_LEN 16384
+
+#define LSAPI_RESP_HTTP_HEADER_MAX 4096
+#define LSAPI_PACKET_HEADER_LEN 8
+
+
+struct lsapi_packet_header
+{
+ char m_versionB0; /* LSAPI protocol version */
+ char m_versionB1;
+ char m_type;
+ char m_flag;
+ union
+ {
+ 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
+*/
+
+struct lsapi_req_header
+{
+ struct lsapi_packet_header m_pktHeader;
+
+ 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_requestMethodOff;
+ int32_t m_cntUnknownHeaders;
+ int32_t m_cntEnv;
+ int32_t m_cntSpecialEnv;
+} ;
+
+
+struct lsapi_http_header_index
+{
+ int16_t m_headerLen[H_TRANSFER_ENCODING+1];
+ int32_t m_headerOff[H_TRANSFER_ENCODING+1];
+} ;
+
+struct lsapi_header_offset
+{
+ int32_t nameOff;
+ int32_t nameLen;
+ int32_t valueOff;
+ int32_t valueLen;
+} ;
+
+struct lsapi_resp_info
+{
+ int32_t m_cntHeaders;
+ int32_t m_status;
+};
+
+struct lsapi_resp_header
+{
+ struct lsapi_packet_header m_pktHeader;
+ struct lsapi_resp_info m_respInfo;
+};
+
+#if defined (c_plusplus) || defined (__cplusplus)
+}
+#endif
+
+
+#endif
+
diff --git a/sapi/litespeed/lsapilib.c b/sapi/litespeed/lsapilib.c
new file mode 100644
index 0000000..10ea749
--- /dev/null
+++ b/sapi/litespeed/lsapilib.c
@@ -0,0 +1,2227 @@
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: George Wang <gwang@litespeedtech.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+/*
+Copyright (c) 2007, Lite Speed Technologies Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of the Lite Speed Technologies Inc nor the
+ names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS 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 COPYRIGHT
+OWNER OR 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.
+*/
+
+#include <lsapilib.h>
+
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.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/resource.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <unistd.h>
+
+#define LSAPI_ST_REQ_HEADER 1
+#define LSAPI_ST_REQ_BODY 2
+#define LSAPI_ST_RESP_HEADER 4
+#define LSAPI_ST_RESP_BODY 8
+
+#define LSAPI_RESP_BUF_SIZE 8192
+#define LSAPI_INIT_RESP_HEADER_LEN 4096
+
+
+static int g_inited = 0;
+static int g_running = 1;
+static int s_ppid;
+static int s_slow_req_msecs = 0;
+LSAPI_Request g_req = { -1, -1 };
+
+void Flush_RespBuf_r( LSAPI_Request * pReq );
+
+static const char *CGI_HEADERS[H_TRANSFER_ENCODING+1] =
+{
+ "HTTP_ACCEPT", "HTTP_ACCEPT_CHARSET",
+ "HTTP_ACCEPT_ENCODING",
+ "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_CONTROL",
+ "HTTP_IF_MODIFIED_SINCE", "HTTP_IF_MATCH",
+ "HTTP_IF_NONE_MATCH",
+ "HTTP_IF_RANGE",
+ "HTTP_IF_UNMODIFIED_SINCE",
+ "HTTP_KEEP_ALIVE",
+ "HTTP_RANGE",
+ "HTTP_X_FORWARDED_FOR",
+ "HTTP_VIA",
+ "HTTP_TRANSFER_ENCODING"
+};
+
+static int CGI_HEADER_LEN[H_TRANSFER_ENCODING+1] = {
+ 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 )
+{
+}
+static void lsapi_siguser1( int sig )
+{
+ g_running = 0;
+}
+
+#ifndef sighandler_t
+typedef void (*sighandler_t)(int);
+#endif
+
+static void lsapi_signal(int signo, sighandler_t handler)
+{
+ struct sigaction sa;
+
+ sigaction(signo, NULL, &sa);
+
+ if (sa.sa_handler == SIG_DFL) {
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = 0;
+ sa.sa_handler = handler;
+ sigaction(signo, &sa, NULL);
+ }
+}
+
+
+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_versionB1 = LSAPI_VERSION_B1;
+ pHeader->m_type = type;
+ pHeader->m_flag = LSAPI_ENDIAN;
+ pHeader->m_packetLen.m_iLen = len;
+}
+
+static int lsapi_set_nblock( int fd, int nonblock )
+{
+ int val = fcntl( fd, F_GETFL, 0 );
+ if ( nonblock )
+ {
+ if (!( val & O_NONBLOCK ))
+ {
+ return fcntl( fd, F_SETFL, val | O_NONBLOCK );
+ }
+ }
+ else
+ {
+ if ( val & O_NONBLOCK )
+ {
+ return fcntl( fd, F_SETFL, val &(~O_NONBLOCK) );
+ }
+ }
+ return 0;
+}
+
+
+static int lsapi_close( int fd )
+{
+ int ret;
+ while( 1 ) {
+ ret = close( fd );
+ if (( ret == -1 )&&( errno == EINTR )&&(g_running)) {
+ continue;
+ }
+ return ret;
+ }
+}
+
+static inline int lsapi_read( int fd, void * pBuf, int len )
+{
+ int ret;
+ while( 1 ) {
+ ret = read( fd, (char *)pBuf, len );
+ if (( ret == -1 )&&( errno == EINTR )&&(g_running)) {
+ continue;
+ }
+ return ret;
+ }
+}
+
+
+static int lsapi_writev( int fd, struct iovec ** pVec, int count, int totalLen )
+{
+ int ret;
+ int left = totalLen;
+ int n = count;
+ while(( left > 0 )&&g_running ) {
+ ret = writev( fd, *pVec, n );
+ if ( ret > 0 ) {
+ left -= ret;
+ if (( left <= 0)||( !g_running )) {
+ return totalLen - left;
+ }
+ while( ret > 0 ) {
+ if ( (*pVec)->iov_len <= ret ) {
+ ret -= (*pVec)->iov_len;
+ ++(*pVec);
+ } else {
+ (*pVec)->iov_base = (char *)(*pVec)->iov_base + ret;
+ (*pVec)->iov_len -= ret;
+ break;
+ }
+ }
+ } 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 inline int allocateBuf( LSAPI_Request * pReq, int size )
+{
+ char * pBuf = (char *)realloc( pReq->m_pReqBuf, size );
+ if ( pBuf ) {
+ pReq->m_pReqBuf = pBuf;
+ pReq->m_reqBufSize = size;
+ pReq->m_pHeader = (struct lsapi_req_header *)pReq->m_pReqBuf;
+ return 0;
+ }
+ return -1;
+}
+
+
+static int allocateIovec( LSAPI_Request * pReq, int n )
+{
+ struct iovec * p = (struct iovec *)realloc(
+ pReq->m_pIovec, sizeof(struct iovec) * n );
+ if ( !p ) {
+ return -1;
+ }
+ pReq->m_pIovecToWrite = p + ( pReq->m_pIovecToWrite - pReq->m_pIovec );
+ pReq->m_pIovecCur = p + ( pReq->m_pIovecCur - pReq->m_pIovec );
+ pReq->m_pIovec = p;
+ pReq->m_pIovecEnd = p + n;
+ return 0;
+}
+
+static int allocateRespHeaderBuf( LSAPI_Request * pReq, int size )
+{
+ char * p = (char *)realloc( pReq->m_pRespHeaderBuf, size );
+ if ( !p ) {
+ return -1;
+ }
+ pReq->m_pRespHeaderBufPos = p + ( pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf );
+ pReq->m_pRespHeaderBuf = p;
+ pReq->m_pRespHeaderBufEnd = p + size;
+ return 0;
+}
+
+
+static inline int verifyHeader( struct lsapi_packet_header * pHeader, char pktType )
+{
+ if (( LSAPI_VERSION_B0 != pHeader->m_versionB0 )||
+ ( LSAPI_VERSION_B1 != pHeader->m_versionB1 )||
+ ( pktType != pHeader->m_type )) {
+ return -1;
+ }
+ if ( LSAPI_ENDIAN != (pHeader->m_flag & LSAPI_ENDIAN_BIT )) {
+ register char b;
+ b = pHeader->m_packetLen.m_bytes[0];
+ pHeader->m_packetLen.m_bytes[0] = pHeader->m_packetLen.m_bytes[3];
+ pHeader->m_packetLen.m_bytes[3] = b;
+ b = pHeader->m_packetLen.m_bytes[1];
+ pHeader->m_packetLen.m_bytes[1] = pHeader->m_packetLen.m_bytes[2];
+ pHeader->m_packetLen.m_bytes[2] = b;
+ }
+ return pHeader->m_packetLen.m_iLen;
+}
+
+static int allocateEnvList( struct LSAPI_key_value_pair ** pEnvList,
+ int *curSize, int newSize )
+{
+ struct LSAPI_key_value_pair * pBuf;
+ if ( *curSize >= newSize ) {
+ return 0;
+ }
+ if ( newSize > 8192 ) {
+ return -1;
+ }
+ pBuf = (struct LSAPI_key_value_pair *)realloc( *pEnvList, newSize *
+ sizeof(struct LSAPI_key_value_pair) );
+ if ( pBuf ) {
+ *pEnvList = pBuf;
+ *curSize = newSize;
+ return 0;
+ } else {
+ return -1;
+ }
+
+}
+
+static inline int isPipe( int fd )
+{
+ char achPeer[128];
+ socklen_t len = 128;
+ if (( getpeername( fd, (struct sockaddr *)achPeer, &len ) != 0 )&&
+ ( errno == ENOTCONN )) {
+ return 0;
+ } else {
+ return 1;
+ }
+}
+
+static int parseEnv( struct LSAPI_key_value_pair * pEnvList, int count,
+ char **pBegin, char * pEnd )
+{
+ struct LSAPI_key_value_pair * pEnvEnd;
+ int keyLen = 0, valLen = 0;
+ if ( count > 8192 ) {
+ return -1;
+ }
+ pEnvEnd = pEnvList + count;
+ while( pEnvList != pEnvEnd ) {
+ if ( pEnd - *pBegin < 4 ) {
+ return -1;
+ }
+ keyLen = *((unsigned char *)((*pBegin)++));
+ keyLen = (keyLen << 8) + *((unsigned char *)((*pBegin)++));
+ valLen = *((unsigned char *)((*pBegin)++));
+ valLen = (valLen << 8) + *((unsigned char *)((*pBegin)++));
+ if ( *pBegin + keyLen + valLen > pEnd ) {
+ return -1;
+ }
+ if (( !keyLen )||( !valLen )) {
+ return -1;
+ }
+
+ pEnvList->pKey = *pBegin;
+ *pBegin += keyLen;
+ pEnvList->pValue = *pBegin;
+ *pBegin += valLen;
+
+ pEnvList->keyLen = keyLen - 1;
+ pEnvList->valLen = valLen - 1;
+ ++pEnvList;
+ }
+ if ( memcmp( *pBegin, "\0\0\0\0", 4 ) != 0 ) {
+ return -1;
+ }
+ *pBegin += 4;
+ return 0;
+}
+
+static inline void swapIntEndian( int * pInteger )
+{
+ char * p = (char *)pInteger;
+ register char b;
+ b = p[0];
+ p[0] = p[3];
+ p[3] = b;
+ b = p[1];
+ p[1] = p[2];
+ p[2] = b;
+
+}
+
+static inline void fixEndian( LSAPI_Request * pReq )
+{
+ struct lsapi_req_header *p= pReq->m_pHeader;
+ swapIntEndian( &p->m_httpHeaderLen );
+ swapIntEndian( &p->m_reqBodyLen );
+ swapIntEndian( &p->m_scriptFileOff );
+ swapIntEndian( &p->m_scriptNameOff );
+ swapIntEndian( &p->m_queryStringOff );
+ swapIntEndian( &p->m_requestMethodOff );
+ swapIntEndian( &p->m_cntUnknownHeaders );
+ swapIntEndian( &p->m_cntEnv );
+ swapIntEndian( &p->m_cntSpecialEnv );
+}
+
+static void fixHeaderIndexEndian( LSAPI_Request * pReq )
+{
+ int i;
+ for( i = 0; i < H_TRANSFER_ENCODING; ++i ) {
+ if ( pReq->m_pHeaderIndex->m_headerOff[i] ) {
+ register char b;
+ char * p = (char *)(&pReq->m_pHeaderIndex->m_headerLen[i]);
+ b = p[0];
+ p[0] = p[1];
+ p[1] = b;
+ swapIntEndian( &pReq->m_pHeaderIndex->m_headerOff[i] );
+ }
+ }
+ if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) {
+ struct lsapi_header_offset * pCur, *pEnd;
+ pCur = pReq->m_pUnknownHeader;
+ pEnd = pCur + pReq->m_pHeader->m_cntUnknownHeaders;
+ while( pCur < pEnd ) {
+ swapIntEndian( &pCur->nameOff );
+ swapIntEndian( &pCur->nameLen );
+ swapIntEndian( &pCur->valueOff );
+ swapIntEndian( &pCur->valueLen );
+ ++pCur;
+ }
+ }
+}
+
+static int parseRequest( LSAPI_Request * pReq, int totalLen )
+{
+ int shouldFixEndian;
+ char * pBegin = pReq->m_pReqBuf + sizeof( struct lsapi_req_header );
+ char * pEnd = pReq->m_pReqBuf + totalLen;
+ shouldFixEndian = ( LSAPI_ENDIAN != (
+ pReq->m_pHeader->m_pktHeader.m_flag & LSAPI_ENDIAN_BIT ) );
+ if ( shouldFixEndian ) {
+ fixEndian( pReq );
+ }
+ if ( (pReq->m_specialEnvListSize < pReq->m_pHeader->m_cntSpecialEnv )&&
+ allocateEnvList( &pReq->m_pSpecialEnvList,
+ &pReq->m_specialEnvListSize,
+ pReq->m_pHeader->m_cntSpecialEnv ) == -1 ) {
+ return -1;
+ }
+ if ( (pReq->m_envListSize < pReq->m_pHeader->m_cntEnv )&&
+ allocateEnvList( &pReq->m_pEnvList, &pReq->m_envListSize,
+ pReq->m_pHeader->m_cntEnv ) == -1 ) {
+ return -1;
+ }
+ if ( parseEnv( pReq->m_pSpecialEnvList,
+ pReq->m_pHeader->m_cntSpecialEnv,
+ &pBegin, pEnd ) == -1 ) {
+ return -1;
+ }
+ if ( parseEnv( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
+ &pBegin, pEnd ) == -1 ) {
+ return -1;
+ }
+ pReq->m_pScriptFile = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptFileOff;
+ pReq->m_pScriptName = pReq->m_pReqBuf + pReq->m_pHeader->m_scriptNameOff;
+ pReq->m_pQueryString = pReq->m_pReqBuf + pReq->m_pHeader->m_queryStringOff;
+ pReq->m_pRequestMethod = pReq->m_pReqBuf + pReq->m_pHeader->m_requestMethodOff;
+
+ pBegin = pReq->m_pReqBuf + (( pBegin - pReq->m_pReqBuf + 7 ) & (~0x7));
+ pReq->m_pHeaderIndex = ( struct lsapi_http_header_index * )pBegin;
+ pBegin += sizeof( struct lsapi_http_header_index );
+
+ pReq->m_pUnknownHeader = (struct lsapi_header_offset *)pBegin;
+ pBegin += sizeof( struct lsapi_header_offset) *
+ pReq->m_pHeader->m_cntUnknownHeaders;
+
+ pReq->m_pHttpHeader = pBegin;
+ pBegin += pReq->m_pHeader->m_httpHeaderLen;
+ if ( pBegin != pEnd ) {
+ return -1;
+ }
+
+ if ( shouldFixEndian ) {
+ fixHeaderIndexEndian( pReq );
+ }
+
+ return 0;
+}
+
+static int s_accept_notify = 0;
+
+static struct lsapi_packet_header ack = {'L', 'S',
+ LSAPI_REQ_RECEIVED, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} };
+static inline int notify_req_received( int fd )
+{
+ if ( write( fd, &ack, LSAPI_PACKET_HEADER_LEN )
+ < LSAPI_PACKET_HEADER_LEN ) {
+ return -1;
+ }
+ return 0;
+}
+
+
+static int readReq( LSAPI_Request * pReq )
+{
+ int len;
+ int packetLen;
+ if ( !pReq ) {
+ return -1;
+ }
+ if ( pReq->m_reqBufSize < 8192 ) {
+ if ( allocateBuf( pReq, 8192 ) == -1 ) {
+ return -1;
+ }
+ }
+
+ while ( pReq->m_bufRead < LSAPI_PACKET_HEADER_LEN ) {
+ len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf, pReq->m_reqBufSize );
+ if ( len <= 0 ) {
+ return -1;
+ }
+ pReq->m_bufRead += len;
+ }
+ pReq->m_reqState = LSAPI_ST_REQ_HEADER;
+
+ packetLen = verifyHeader( &pReq->m_pHeader->m_pktHeader, LSAPI_BEGIN_REQUEST );
+ if ( packetLen < 0 ) {
+ return -1;
+ }
+ if ( packetLen > LSAPI_MAX_HEADER_LEN ) {
+ return -1;
+ }
+
+ if ( packetLen + 1024 > pReq->m_reqBufSize ) {
+ if ( allocateBuf( pReq, packetLen + 1024 ) == -1 ) {
+ return -1;
+ }
+ }
+ while( packetLen > pReq->m_bufRead ) {
+ len = lsapi_read( pReq->m_fd, pReq->m_pReqBuf + pReq->m_bufRead, packetLen - pReq->m_bufRead );
+ if ( len <= 0 ) {
+ return -1;
+ }
+ pReq->m_bufRead += len;
+ }
+ if ( parseRequest( pReq, packetLen ) < 0 ) {
+ return -1;
+ }
+ pReq->m_bufProcessed = packetLen;
+ pReq->m_reqState = LSAPI_ST_REQ_BODY | LSAPI_ST_RESP_HEADER;
+
+ if ( !s_accept_notify )
+ return notify_req_received( pReq->m_fd );
+ else
+ return 0;
+}
+
+
+
+int LSAPI_Init(void)
+{
+ if ( !g_inited ) {
+ lsapi_signal(SIGPIPE, lsapi_sigpipe);
+ lsapi_signal(SIGUSR1, lsapi_siguser1);
+
+#if defined(SIGXFSZ) && defined(SIG_IGN)
+ signal(SIGXFSZ, SIG_IGN);
+#endif
+ /* let STDOUT function as STDERR,
+ just in case writing to STDOUT directly */
+ dup2( 2, 1 );
+
+ if ( LSAPI_InitRequest( &g_req, LSAPI_SOCK_FILENO ) == -1 ) {
+ return -1;
+ }
+ g_inited = 1;
+ s_ppid = getppid();
+ }
+ return 0;
+}
+
+void LSAPI_Stop(void)
+{
+ g_running = 0;
+}
+
+int LSAPI_IsRunning(void)
+{
+ return g_running;
+}
+
+int LSAPI_InitRequest( LSAPI_Request * pReq, int fd )
+{
+ if ( !pReq ) {
+ return -1;
+ }
+ memset( pReq, 0, sizeof( LSAPI_Request ) );
+ if ( allocateIovec( pReq, 16 ) == -1 ) {
+ return -1;
+ }
+ pReq->m_pRespBuf = pReq->m_pRespBufPos = (char *)malloc( LSAPI_RESP_BUF_SIZE );
+ if ( !pReq->m_pRespBuf ) {
+ return -1;
+ }
+ pReq->m_pRespBufEnd = pReq->m_pRespBuf + LSAPI_RESP_BUF_SIZE;
+ pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
+ pReq->m_respPktHeaderEnd = &pReq->m_respPktHeader[5];
+ if ( allocateRespHeaderBuf( pReq, LSAPI_INIT_RESP_HEADER_LEN ) == -1 ) {
+ return -1;
+ }
+
+ if ( isPipe( fd ) ) {
+ pReq->m_fdListen = -1;
+ pReq->m_fd = fd;
+ } else {
+ pReq->m_fdListen = fd;
+ pReq->m_fd = -1;
+ lsapi_set_nblock( fd, 1 );
+ }
+ return 0;
+}
+
+int LSAPI_Is_Listen( void )
+{
+ return LSAPI_Is_Listen_r( &g_req );
+}
+
+int LSAPI_Is_Listen_r( LSAPI_Request * pReq)
+{
+ return pReq->m_fdListen != -1;
+}
+
+
+
+int LSAPI_Accept_r( LSAPI_Request * pReq )
+{
+ char achPeer[128];
+ socklen_t len;
+ int nodelay = 1;
+
+ if ( !pReq ) {
+ return -1;
+ }
+ if ( LSAPI_Finish_r( pReq ) == -1 ) {
+ return -1;
+ }
+ while( g_running ) {
+ if ( pReq->m_fd == -1 ) {
+ if ( pReq->m_fdListen != -1) {
+ len = sizeof( achPeer );
+ pReq->m_fd = accept( pReq->m_fdListen,
+ (struct sockaddr *)&achPeer, &len );
+ if ( pReq->m_fd == -1 ) {
+ if (( errno == EINTR )||( errno == EAGAIN)) {
+ continue;
+ } else {
+ return -1;
+ }
+ } else {
+ lsapi_set_nblock( pReq->m_fd , 0 );
+ if (((struct sockaddr *)&achPeer)->sa_family == AF_INET ) {
+ setsockopt(pReq->m_fd, IPPROTO_TCP, TCP_NODELAY,
+ (char *)&nodelay, sizeof(nodelay));
+ }
+
+ if ( s_accept_notify )
+ return notify_req_received( pReq->m_fd );
+
+ }
+ } else {
+ return -1;
+ }
+ }
+ if ( !readReq( pReq ) ) {
+ break;
+ }
+ lsapi_close( pReq->m_fd );
+ pReq->m_fd = -1;
+ LSAPI_Reset_r( pReq );
+ }
+ return 0;
+}
+
+static struct lsapi_packet_header finish = {'L', 'S',
+ LSAPI_RESP_END, LSAPI_ENDIAN, {LSAPI_PACKET_HEADER_LEN} };
+
+int LSAPI_Finish_r( LSAPI_Request * pReq )
+{
+ /* finish req body */
+ if ( !pReq ) {
+ return -1;
+ }
+ if (pReq->m_reqState) {
+ if ( pReq->m_fd != -1 ) {
+ if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) {
+ LSAPI_FinalizeRespHeaders_r( pReq );
+ }
+ if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) {
+ Flush_RespBuf_r( pReq );
+ }
+
+ pReq->m_pIovecCur->iov_base = (void *)&finish;
+ pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
+ pReq->m_totalLen += LSAPI_PACKET_HEADER_LEN;
+ ++pReq->m_pIovecCur;
+ LSAPI_Flush_r( pReq );
+ }
+ LSAPI_Reset_r( pReq );
+ }
+ return 0;
+}
+
+
+void LSAPI_Reset_r( LSAPI_Request * pReq )
+{
+ pReq->m_pRespBufPos = pReq->m_pRespBuf;
+ pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec + 1;
+ pReq->m_pRespHeaderBufPos = pReq->m_pRespHeaderBuf;
+
+ memset( &pReq->m_pHeaderIndex, 0,
+ (char *)(pReq->m_respHeaderLen) - (char *)&pReq->m_pHeaderIndex );
+}
+
+
+int LSAPI_Release_r( LSAPI_Request * pReq )
+{
+ if ( pReq->m_pReqBuf ) {
+ free( pReq->m_pReqBuf );
+ }
+ if ( pReq->m_pSpecialEnvList ) {
+ free( pReq->m_pSpecialEnvList );
+ }
+ if ( pReq->m_pEnvList ) {
+ free( pReq->m_pEnvList );
+ }
+ if ( pReq->m_pRespHeaderBuf ) {
+ free( pReq->m_pRespHeaderBuf );
+ }
+ return 0;
+}
+
+
+char * LSAPI_GetHeader_r( LSAPI_Request * pReq, int headerIndex )
+{
+ int off;
+ if ( !pReq || ((unsigned int)headerIndex > H_TRANSFER_ENCODING) ) {
+ return NULL;
+ }
+ off = pReq->m_pHeaderIndex->m_headerOff[ headerIndex ];
+ if ( !off ) {
+ return NULL;
+ }
+ if ( *(pReq->m_pHttpHeader + off +
+ pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) ) {
+ *( pReq->m_pHttpHeader + off +
+ pReq->m_pHeaderIndex->m_headerLen[ headerIndex ]) = 0;
+ }
+ 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 || (pReq->m_fd ==-1) || ( !pBuf )||(bufLen < 0 )) {
+ return -1;
+ }
+ total = pReq->m_pHeader->m_reqBodyLen - pReq->m_reqBodyRead;
+
+ if ( total <= 0 ) {
+ return 0;
+ }
+ if ( total < bufLen ) {
+ bufLen = total;
+ }
+
+ total = 0;
+ len = pReq->m_bufRead - pReq->m_bufProcessed;
+ if ( len > 0 ) {
+ if ( len > bufLen ) {
+ len = bufLen;
+ }
+ memmove( pBuf, pReq->m_pReqBuf + pReq->m_bufProcessed, len );
+ pReq->m_bufProcessed += len;
+ total += len;
+ pBuf += len;
+ bufLen -= len;
+ }
+ while( bufLen > 0 ) {
+ len = lsapi_read( pReq->m_fd, pBuf, bufLen );
+ if ( len > 0 ) {
+ total += len;
+ pBuf += len;
+ bufLen -= len;
+ } else {
+ if ( len <= 0 ) {
+ if ( !total) {
+ return -1;
+ }
+ break;
+ }
+ }
+ }
+ pReq->m_reqBodyRead += total;
+ return total;
+
+}
+
+
+int LSAPI_Write_r( LSAPI_Request * pReq, const char * pBuf, int len )
+{
+ struct lsapi_packet_header * pHeader;
+ const char * pEnd;
+ const char * p;
+ int bufLen;
+ int toWrite;
+ int packetLen;
+
+ if ( !pReq || !pBuf || (pReq->m_fd == -1) ) {
+ return -1;
+ }
+ if ( len < pReq->m_pRespBufEnd - pReq->m_pRespBufPos ) {
+ memmove( pReq->m_pRespBufPos, pBuf, len );
+ pReq->m_pRespBufPos += len;
+ return len;
+ }
+
+ if ( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) {
+ LSAPI_FinalizeRespHeaders_r( pReq );
+ }
+ pReq->m_reqState |= LSAPI_ST_RESP_BODY;
+
+ pHeader = pReq->m_respPktHeader;
+ p = pBuf;
+ pEnd = pBuf + len;
+ bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf;
+
+ while( ( toWrite = pEnd - p ) > 0 ) {
+ packetLen = toWrite + bufLen;
+ if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) {
+ packetLen = LSAPI_MAX_DATA_PACKET_LEN;
+ toWrite = packetLen - bufLen;
+ }
+
+ lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
+ packetLen + LSAPI_PACKET_HEADER_LEN );
+ pReq->m_totalLen += packetLen + LSAPI_PACKET_HEADER_LEN;
+
+ pReq->m_pIovecCur->iov_base = (void *)pHeader;
+ pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
+ ++pReq->m_pIovecCur;
+ ++pHeader;
+ if ( bufLen > 0 ) {
+ pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
+ pReq->m_pIovecCur->iov_len = bufLen;
+ pReq->m_pRespBufPos = pReq->m_pRespBuf;
+ ++pReq->m_pIovecCur;
+ bufLen = 0;
+ }
+
+ pReq->m_pIovecCur->iov_base = (void *)p;
+ pReq->m_pIovecCur->iov_len = toWrite;
+ ++pReq->m_pIovecCur;
+ p += toWrite;
+
+ if ( pHeader >= pReq->m_respPktHeaderEnd - 1) {
+ if ( LSAPI_Flush_r( pReq ) == -1 ) {
+ return -1;
+ }
+ pHeader = pReq->m_respPktHeader;
+ }
+ }
+ if ( pHeader != pReq->m_respPktHeader ) {
+ if ( LSAPI_Flush_r( pReq ) == -1 ) {
+ return -1;
+ }
+ }
+ return p - pBuf;
+}
+
+void Flush_RespBuf_r( LSAPI_Request * pReq )
+{
+ struct lsapi_packet_header * pHeader = pReq->m_respPktHeader;
+ int bufLen = pReq->m_pRespBufPos - pReq->m_pRespBuf;
+ pReq->m_reqState |= LSAPI_ST_RESP_BODY;
+ lsapi_buildPacketHeader( pHeader, LSAPI_RESP_STREAM,
+ bufLen + LSAPI_PACKET_HEADER_LEN );
+ pReq->m_totalLen += bufLen + LSAPI_PACKET_HEADER_LEN;
+
+ pReq->m_pIovecCur->iov_base = (void *)pHeader;
+ pReq->m_pIovecCur->iov_len = LSAPI_PACKET_HEADER_LEN;
+ ++pReq->m_pIovecCur;
+ ++pHeader;
+ if ( bufLen > 0 ) {
+ pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespBuf;
+ pReq->m_pIovecCur->iov_len = bufLen;
+ pReq->m_pRespBufPos = pReq->m_pRespBuf;
+ ++pReq->m_pIovecCur;
+ bufLen = 0;
+ }
+}
+
+
+
+
+int LSAPI_Flush_r( LSAPI_Request * pReq )
+{
+ int ret = 0;
+ 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 );
+ }
+ if ( pReq->m_pRespBufPos != pReq->m_pRespBuf ) {
+ Flush_RespBuf_r( pReq );
+ }
+
+ n = pReq->m_pIovecCur - pReq->m_pIovecToWrite;
+ if ( n > 0 ) {
+
+ ret = lsapi_writev( pReq->m_fd, &pReq->m_pIovecToWrite,
+ n, pReq->m_totalLen );
+ if ( ret < pReq->m_totalLen ) {
+ lsapi_close( pReq->m_fd );
+ pReq->m_fd = -1;
+ ret = -1;
+ }
+ pReq->m_totalLen = 0;
+ pReq->m_pIovecCur = pReq->m_pIovecToWrite = pReq->m_pIovec;
+ }
+ return ret;
+}
+
+
+int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len )
+{
+ struct lsapi_packet_header header;
+ const char * pEnd;
+ const char * p;
+ int packetLen;
+ int totalLen;
+ int ret;
+ 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 );
+ }
+
+ p = pBuf;
+ pEnd = pBuf + len;
+
+ while( ( packetLen = pEnd - p ) > 0 ) {
+ if ( LSAPI_MAX_DATA_PACKET_LEN < packetLen) {
+ packetLen = LSAPI_MAX_DATA_PACKET_LEN;
+ }
+
+ lsapi_buildPacketHeader( &header, LSAPI_STDERR_STREAM,
+ packetLen + LSAPI_PACKET_HEADER_LEN );
+ totalLen = packetLen + LSAPI_PACKET_HEADER_LEN;
+
+ iov[0].iov_base = (void *)&header;
+ iov[0].iov_len = LSAPI_PACKET_HEADER_LEN;
+
+ iov[1].iov_base = (void *)p;
+ iov[1].iov_len = packetLen;
+ p += packetLen;
+ pIov = iov;
+ ret = lsapi_writev( pReq->m_fd, &pIov,
+ 2, totalLen );
+ if ( ret < totalLen ) {
+ lsapi_close( pReq->m_fd );
+ pReq->m_fd = -1;
+ ret = -1;
+ }
+ }
+ 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 )
+{
+ struct LSAPI_key_value_pair * pBegin = pReq->m_pEnvList;
+ 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 ) {
+ return pBegin->pValue;
+ }
+ ++pBegin;
+ }
+ 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 )
+{
+ 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)( CGI_HEADERS[i], CGI_HEADER_LEN[i],
+ pValue, len, arg );
+ ++count;
+ if ( ret <= 0 ) {
+ return ret;
+ }
+ }
+ }
+ if ( pReq->m_pHeader->m_cntUnknownHeaders > 0 ) {
+ char achHeaderName[256];
+ 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;
+ if ( keyLen > 250 ) {
+ keyLen = 250;
+ }
+
+ pKeyEnd = pKey + keyLen;
+ memcpy( achHeaderName, "HTTP_", 5 );
+ p = &achHeaderName[5];
+
+ while( pKey < pKeyEnd ) {
+ char ch = *pKey++;
+ if ( ch == '-' ) {
+ *p++ = '_';
+ } else {
+ *p++ = toupper( ch );
+ }
+ }
+ *p = 0;
+ keyLen += 5;
+
+ pValue = pReq->m_pHttpHeader + pCur->valueOff;
+ *(pValue + pCur->valueLen ) = 0;
+ ret = (*fn)( achHeaderName, keyLen,
+ pValue, pCur->valueLen, arg );
+ if ( ret <= 0 ) {
+ return ret;
+ }
+ ++pCur;
+ }
+ }
+ return count + pReq->m_pHeader->m_cntUnknownHeaders;
+
+}
+
+static int EnvForeach( struct LSAPI_key_value_pair * pEnv,
+ int n, LSAPI_CB_EnvHandler fn, void * arg )
+{
+ struct LSAPI_key_value_pair * pEnd = pEnv + n;
+ int ret;
+ if ( !pEnv || !fn ) {
+ return -1;
+ }
+ while( pEnv < pEnd ) {
+ ret = (*fn)( pEnv->pKey, pEnv->keyLen,
+ pEnv->pValue, pEnv->valLen, arg );
+ if ( ret <= 0 ) {
+ return ret;
+ }
+ ++pEnv;
+ }
+ return n;
+}
+
+
+
+int LSAPI_ForeachEnv_r( LSAPI_Request * pReq,
+ LSAPI_CB_EnvHandler fn, void * arg )
+{
+ if ( !pReq || !fn ) {
+ return -1;
+ }
+ if ( pReq->m_pHeader->m_cntEnv > 0 ) {
+ return EnvForeach( pReq->m_pEnvList, pReq->m_pHeader->m_cntEnv,
+ fn, arg );
+ }
+ return 0;
+}
+
+
+
+int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
+ LSAPI_CB_EnvHandler fn, void * arg )
+{
+ if ( !pReq || !fn ) {
+ return -1;
+ }
+ if ( pReq->m_pHeader->m_cntSpecialEnv > 0 ) {
+ return EnvForeach( pReq->m_pSpecialEnvList,
+ pReq->m_pHeader->m_cntSpecialEnv,
+ fn, arg );
+ }
+ return 0;
+
+}
+
+
+
+int LSAPI_FinalizeRespHeaders_r( LSAPI_Request * pReq )
+{
+ if ( !pReq || !pReq->m_pIovec ) {
+ return -1;
+ }
+ if ( !( pReq->m_reqState & LSAPI_ST_RESP_HEADER ) ) {
+ return 0;
+ }
+ pReq->m_reqState &= ~LSAPI_ST_RESP_HEADER;
+ if ( pReq->m_pRespHeaderBufPos > pReq->m_pRespHeaderBuf ) {
+ pReq->m_pIovecCur->iov_base = (void *)pReq->m_pRespHeaderBuf;
+ pReq->m_pIovecCur->iov_len = pReq->m_pRespHeaderBufPos - pReq->m_pRespHeaderBuf;
+ pReq->m_totalLen += pReq->m_pIovecCur->iov_len;
+ ++pReq->m_pIovecCur;
+ }
+
+ pReq->m_pIovec->iov_len = sizeof( struct lsapi_resp_header)
+ + pReq->m_respHeader.m_respInfo.m_cntHeaders * sizeof( short );
+ pReq->m_totalLen += pReq->m_pIovec->iov_len;
+
+ lsapi_buildPacketHeader( &pReq->m_respHeader.m_pktHeader,
+ LSAPI_RESP_HEADER, pReq->m_totalLen );
+ pReq->m_pIovec->iov_base = (void *)&pReq->m_respHeader;
+ pReq->m_pIovecToWrite = pReq->m_pIovec;
+ return 0;
+}
+
+
+
+
+int LSAPI_AppendRespHeader_r( LSAPI_Request * pReq, char * pBuf, int len )
+{
+ if ( !pReq || !pBuf || len <= 0 || len > LSAPI_RESP_HTTP_HEADER_MAX ) {
+ return -1;
+ }
+ if ( pReq->m_reqState & LSAPI_ST_RESP_BODY ) {
+ return -1;
+ }
+ if ( pReq->m_respHeader.m_respInfo.m_cntHeaders >= LSAPI_MAX_RESP_HEADERS ) {
+ return -1;
+ }
+ if ( pReq->m_pRespHeaderBufPos + len + 1 > pReq->m_pRespHeaderBufEnd ) {
+ int newlen = pReq->m_pRespHeaderBufPos + len + 4096 - pReq->m_pRespHeaderBuf;
+ newlen -= newlen % 4096;
+ if ( allocateRespHeaderBuf( pReq, newlen ) == -1 ) {
+ return -1;
+ }
+ }
+ memmove( pReq->m_pRespHeaderBufPos, pBuf, len );
+ pReq->m_pRespHeaderBufPos += len;
+ *pReq->m_pRespHeaderBufPos++ = 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( *pBind ) ) {
+ ++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 > 65535 )) {
+ 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));
+ }
+
+ if ( s_accept_notify )
+ notify_req_received( fd );
+ }
+ 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;
+ lsapi_set_nblock( pReq->m_fd, 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;
+ lsapi_set_nblock( fd, 0 );
+ } else {
+ if (( errno == EINTR )||( errno == EAGAIN)) {
+ continue;
+ }
+ 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_Set_Slow_Req_Msecs( int msecs )
+{
+ s_slow_req_msecs = msecs;
+}
+
+int LSAPI_Get_Slow_Req_Msecs()
+{
+ return s_slow_req_msecs;
+}
+
+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_ACCEPT_NOTIFY" );
+ if ( p ) {
+ s_accept_notify = atoi( p );
+ }
+
+ p = getenv( "LSAPI_SLOW_REQ_MSECS" );
+ if ( p ) {
+ n = atoi( p );
+ LSAPI_Set_Slow_Req_Msecs( n );
+ }
+
+
+#if defined( RLIMIT_CORE )
+ p = getenv( "LSAPI_ALLOW_CORE_DUMP" );
+ if ( !p ) {
+ struct rlimit limit = { 0, 0 };
+ setrlimit( RLIMIT_CORE, &limit );
+ }
+#endif
+
+ 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();
+}
+
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: sw=4 ts=4 fdm=marker
+ * vim<600: sw=4 ts=4
+ */
+
+
diff --git a/sapi/litespeed/lsapilib.h b/sapi/litespeed/lsapilib.h
new file mode 100644
index 0000000..3a987b4
--- /dev/null
+++ b/sapi/litespeed/lsapilib.h
@@ -0,0 +1,363 @@
+
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 5 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 1997-2013 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available at through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt. |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Author: George Wang <gwang@litespeedtech.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/*
+Copyright (c) 2007, Lite Speed Technologies Inc.
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * 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.
+ * Neither the name of the Lite Speed Technologies Inc nor the
+ names of its contributors may be used to endorse or promote
+ products derived from this software without specific prior
+ written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS 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 COPYRIGHT
+OWNER OR 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.
+*/
+
+
+
+#ifndef _LSAPILIB_H_
+#define _LSAPILIB_H_
+
+#if defined (c_plusplus) || defined (__cplusplus)
+extern "C" {
+#endif
+
+#include <stddef.h>
+#include <lsapidef.h>
+
+#include <sys/time.h>
+#include <sys/types.h>
+
+struct LSAPI_key_value_pair
+{
+ char * pKey;
+ char * pValue;
+ int keyLen;
+ int valLen;
+};
+
+
+#define LSAPI_MAX_RESP_HEADERS 100
+
+typedef struct lsapi_request
+{
+ int m_fdListen;
+ int m_fd;
+
+ long m_lLastActive;
+ long m_lReqBegin;
+
+ char * m_pReqBuf;
+ int m_reqBufSize;
+
+ char * m_pRespBuf;
+ char * m_pRespBufEnd;
+ char * m_pRespBufPos;
+
+ char * m_pRespHeaderBuf;
+ char * m_pRespHeaderBufEnd;
+ char * m_pRespHeaderBufPos;
+
+
+ struct iovec * m_pIovec;
+ struct iovec * m_pIovecEnd;
+ struct iovec * m_pIovecCur;
+ struct iovec * m_pIovecToWrite;
+
+ struct lsapi_packet_header * m_respPktHeaderEnd;
+
+ struct lsapi_req_header * m_pHeader;
+ struct LSAPI_key_value_pair * m_pEnvList;
+ struct LSAPI_key_value_pair * m_pSpecialEnvList;
+ int m_envListSize;
+ int m_specialEnvListSize;
+
+ struct lsapi_http_header_index * m_pHeaderIndex;
+ struct lsapi_header_offset * m_pUnknownHeader;
+
+ char * m_pScriptFile;
+ char * m_pScriptName;
+ char * m_pQueryString;
+ char * m_pHttpHeader;
+ char * m_pRequestMethod;
+ int m_totalLen;
+ int m_reqState;
+ int m_reqBodyRead;
+ int m_bufProcessed;
+ int m_bufRead;
+
+ struct lsapi_packet_header m_respPktHeader[5];
+
+ struct lsapi_resp_header m_respHeader;
+ short m_respHeaderLen[LSAPI_MAX_RESP_HEADERS];
+
+}LSAPI_Request;
+
+extern LSAPI_Request g_req;
+
+
+/* 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);
+
+int LSAPI_Is_Listen_r( LSAPI_Request * pReq);
+
+int LSAPI_InitRequest( LSAPI_Request * pReq, int fd );
+
+int LSAPI_Accept_r( LSAPI_Request * pReq );
+
+void LSAPI_Reset_r( LSAPI_Request * pReq );
+
+int LSAPI_Finish_r( LSAPI_Request * pReq );
+
+int LSAPI_Release_r( LSAPI_Request * pReq );
+
+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 );
+
+int LSAPI_ForeachSpecialEnv_r( LSAPI_Request * pReq,
+ LSAPI_CB_EnvHandler fn, void * arg );
+
+char * LSAPI_GetEnv_r( LSAPI_Request * pReq, const char * name );
+
+
+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 );
+
+int LSAPI_Write_Stderr_r( LSAPI_Request * pReq, const char * pBuf, int len );
+
+int LSAPI_Flush_r( LSAPI_Request * pReq );
+
+int LSAPI_AppendRespHeader_r( LSAPI_Request * pHeader, char * pBuf, int len );
+
+static inline int LSAPI_SetRespStatus_r( LSAPI_Request * pReq, int code )
+{
+ if ( !pReq )
+ return -1;
+ pReq->m_respHeader.m_respInfo.m_status = code;
+ return 0;
+}
+
+static inline char * LSAPI_GetQueryString_r( LSAPI_Request * pReq )
+{
+ if ( pReq )
+ return pReq->m_pQueryString;
+ return NULL;
+}
+
+
+static inline char * LSAPI_GetScriptFileName_r( LSAPI_Request * pReq )
+{
+ if ( pReq )
+ return pReq->m_pScriptFile;
+ return NULL;
+}
+
+
+static inline char * LSAPI_GetScriptName_r( LSAPI_Request * pReq )
+{
+ if ( pReq )
+ return pReq->m_pScriptName;
+ return NULL;
+}
+
+
+static inline char * LSAPI_GetRequestMethod_r( LSAPI_Request * pReq)
+{
+ if ( pReq )
+ return pReq->m_pRequestMethod;
+ return NULL;
+}
+
+
+
+static inline int LSAPI_GetReqBodyLen_r( LSAPI_Request * pReq )
+{
+ if ( pReq )
+ return pReq->m_pHeader->m_reqBodyLen;
+ 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);
+
+static inline int LSAPI_Accept( void )
+{ return LSAPI_Accept_r( &g_req ); }
+
+static inline int LSAPI_Finish(void)
+{ return LSAPI_Finish_r( &g_req ); }
+
+static inline char * LSAPI_GetHeader( int headerIndex )
+{ return LSAPI_GetHeader_r( &g_req, 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 ); }
+
+static inline int LSAPI_ForeachSpecialEnv( LSAPI_CB_EnvHandler fn, void * arg )
+{ return LSAPI_ForeachSpecialEnv_r( &g_req, fn, arg ); }
+
+static inline char * LSAPI_GetEnv( const char * name )
+{ return LSAPI_GetEnv_r( &g_req, name ); }
+
+static inline char * LSAPI_GetQueryString()
+{ return LSAPI_GetQueryString_r( &g_req ); }
+
+static inline char * LSAPI_GetScriptFileName()
+{ return LSAPI_GetScriptFileName_r( &g_req ); }
+
+static inline char * LSAPI_GetScriptName()
+{ return LSAPI_GetScriptName_r( &g_req ); }
+
+static inline char * LSAPI_GetRequestMethod()
+{ return LSAPI_GetRequestMethod_r( &g_req ); }
+
+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 ); }
+
+static inline int LSAPI_Write( const char * pBuf, int len )
+{ return LSAPI_Write_r( &g_req, pBuf, len ); }
+
+static inline int LSAPI_Write_Stderr( const char * pBuf, int len )
+{ return LSAPI_Write_Stderr_r( &g_req, pBuf, len ); }
+
+static inline int LSAPI_Flush()
+{ return LSAPI_Flush_r( &g_req ); }
+
+static inline int LSAPI_AppendRespHeader( char * pBuf, int len )
+{ return LSAPI_AppendRespHeader_r( &g_req, pBuf, 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 );
+
+void LSAPI_Set_Slow_Req_Msecs( int msecs );
+
+int LSAPI_Get_Slow_Req_Msecs( );
+
+
+#if defined (c_plusplus) || defined (__cplusplus)
+}
+#endif
+
+
+#endif
+
+
+
+
+
+
+