diff options
Diffstat (limited to 'sapi/cgi/cgi_main.c')
-rw-r--r-- | sapi/cgi/cgi_main.c | 192 |
1 files changed, 176 insertions, 16 deletions
diff --git a/sapi/cgi/cgi_main.c b/sapi/cgi/cgi_main.c index 896635711b..ef75d980dd 100644 --- a/sapi/cgi/cgi_main.c +++ b/sapi/cgi/cgi_main.c @@ -35,6 +35,7 @@ #ifdef PHP_WIN32 # include "win32/time.h" # include "win32/signal.h" +# include "win32/winutil.h" # include <process.h> #endif @@ -102,7 +103,6 @@ struct sigaction act, old_term, old_quit, old_int; static void (*php_php_import_environment_variables)(zval *array_ptr); -#ifndef PHP_WIN32 /* these globals used for forking children on unix systems */ /** * Number of child processes that will get created to service requests @@ -115,6 +115,7 @@ static int children = 0; */ static int parent = 1; +#ifndef PHP_WIN32 /* Did parent received exit signals SIG_TERM/SIG_INT/SIG_QUIT */ static int exit_signal = 0; @@ -222,6 +223,14 @@ static php_cgi_globals_struct php_cgi_globals; #define TRANSLATE_SLASHES(path) #endif +#ifdef PHP_WIN32 +#define WIN32_MAX_SPAWN_CHILDREN 64 +HANDLE kid_cgi_ps[WIN32_MAX_SPAWN_CHILDREN]; +int kids; +HANDLE job = NULL; +JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_info = { 0 }; +#endif + #ifndef HAVE_ATTRIBUTE_WEAK static void fcgi_log(int type, const char *format, ...) { va_list ap; @@ -267,8 +276,9 @@ static int print_extension_info(zend_extension *ext, void *arg) static int extension_name_cmp(const zend_llist_element **f, const zend_llist_element **s) { - return strcmp( ((zend_extension *)(*f)->data)->name, - ((zend_extension *)(*s)->data)->name); + zend_extension *fe = (zend_extension*)(*f)->data; + zend_extension *se = (zend_extension*)(*s)->data; + return strcmp(fe->name, se->name); } static void print_extensions(void) @@ -354,9 +364,7 @@ static void sapi_fcgi_flush(void *server_context) fcgi_request *request = (fcgi_request*) server_context; if ( -#ifndef PHP_WIN32 !parent && -#endif request && !fcgi_flush(request, 0)) { php_handle_aborted_connection(); @@ -703,7 +711,7 @@ static void sapi_cgi_register_variables(zval *track_vars_array) } } -static void sapi_cgi_log_message(char *message) +static void sapi_cgi_log_message(char *message, int syslog_type_int) { if (fcgi_is_fastcgi() && CGIG(fcgi_logging)) { fcgi_request *request; @@ -900,9 +908,7 @@ static int sapi_cgi_deactivate(void) if (SG(sapi_started)) { if (fcgi_is_fastcgi()) { if ( -#ifndef PHP_WIN32 !parent && -#endif !fcgi_finish_request((fcgi_request*)SG(server_context), 0)) { php_handle_aborted_connection(); } @@ -964,7 +970,7 @@ ZEND_END_ARG_INFO() static const zend_function_entry additional_functions[] = { ZEND_FE(dl, arginfo_dl) - {NULL, NULL, NULL} + PHP_FE_END }; /* {{{ php_cgi_usage @@ -1431,6 +1437,29 @@ void fastcgi_cleanup(int signal) exit(0); } } +#else +BOOL WINAPI fastcgi_cleanup(DWORD sig) +{ + int i = kids; + + while (0 < i--) { + if (NULL == kid_cgi_ps[i]) { + continue; + } + + TerminateProcess(kid_cgi_ps[i], 0); + CloseHandle(kid_cgi_ps[i]); + kid_cgi_ps[i] = NULL; + } + + if (job) { + CloseHandle(job); + } + + parent = 0; + + return TRUE; +} #endif PHP_INI_BEGIN() @@ -1688,7 +1717,7 @@ const zend_function_entry cgi_functions[] = { PHP_FE(apache_request_headers, arginfo_no_args) PHP_FE(apache_response_headers, arginfo_no_args) PHP_FALIAS(getallheaders, apache_request_headers, arginfo_no_args) - {NULL, NULL, NULL} + PHP_FE_END }; static zend_module_entry cgi_module_entry = { @@ -1772,9 +1801,7 @@ int main(int argc, char *argv[]) ZEND_TSRMLS_CACHE_UPDATE(); #endif -#ifdef ZEND_SIGNALS zend_signal_startup(); -#endif #ifdef ZTS ts_allocate_id(&php_cgi_globals_id, sizeof(php_cgi_globals_struct), (ts_allocate_ctor) php_cgi_globals_ctor, NULL); @@ -1979,8 +2006,7 @@ consult the installation file that came with this distribution, or visit \n\ /* library is already initialized, now init our request */ request = fcgi_init_request(fcgi_fd, NULL, NULL, NULL); -#ifndef PHP_WIN32 - /* Pre-fork, if required */ + /* Pre-fork or spawn, if required */ if (getenv("PHP_FCGI_CHILDREN")) { char * children_str = getenv("PHP_FCGI_CHILDREN"); children = atoi(children_str); @@ -1992,10 +2018,27 @@ consult the installation file that came with this distribution, or visit \n\ /* This is the number of concurrent requests, equals FCGI_MAX_CONNS */ fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, children_str, strlen(children_str)); } else { +#ifdef PHP_WIN32 + /* If this env var is set, the process was invoked as a child. Let + it show the original PHP_FCGI_CHILDREN value, while don't care + otherwise. */ + char * children_str = getenv("PHP_FCGI_CHILDREN_FOR_KID"); + if (children_str) { + char putenv_buf[sizeof("PHP_FCGI_CHILDREN")+5]; + + snprintf(putenv_buf, sizeof(putenv_buf), "%s=%s", "PHP_FCGI_CHILDREN", children_str); + putenv(putenv_buf); + putenv("PHP_FCGI_CHILDREN_FOR_KID="); + + SetEnvironmentVariable("PHP_FCGI_CHILDREN", children_str); + SetEnvironmentVariable("PHP_FCGI_CHILDREN_FOR_KID", NULL); + } +#endif fcgi_set_mgmt_var("FCGI_MAX_CONNS", sizeof("FCGI_MAX_CONNS")-1, "1", sizeof("1")-1); fcgi_set_mgmt_var("FCGI_MAX_REQS", sizeof("FCGI_MAX_REQS")-1, "1", sizeof("1")-1); } +#ifndef PHP_WIN32 if (children) { int running = 0; pid_t pid; @@ -2040,6 +2083,7 @@ consult the installation file that came with this distribution, or visit \n\ sigaction(SIGTERM, &old_term, 0); sigaction(SIGQUIT, &old_quit, 0); sigaction(SIGINT, &old_int, 0); + zend_signal_init(); break; case -1: perror("php (pre-forking)"); @@ -2079,8 +2123,126 @@ consult the installation file that came with this distribution, or visit \n\ } } else { parent = 0; + zend_signal_init(); } +#else + if (children) { + wchar_t *cmd_line_tmp, cmd_line[PHP_WIN32_IOUTIL_MAXPATHLEN]; + size_t cmd_line_len; + char kid_buf[16]; + int i; + + ZeroMemory(&kid_cgi_ps, sizeof(kid_cgi_ps)); + kids = children < WIN32_MAX_SPAWN_CHILDREN ? children : WIN32_MAX_SPAWN_CHILDREN; + + SetConsoleCtrlHandler(fastcgi_cleanup, TRUE); + + /* kids will inherit the env, don't let them spawn */ + SetEnvironmentVariable("PHP_FCGI_CHILDREN", NULL); + /* instead, set a temporary env var, so then the child can read and + show the actual setting correctly. */ + snprintf(kid_buf, 16, "%d", children); + SetEnvironmentVariable("PHP_FCGI_CHILDREN_FOR_KID", kid_buf); + + /* The current command line is used as is. This should normally be no issue, + even if there were some I/O redirection. If some issues turn out, an + extra parsing might be needed here. */ + cmd_line_tmp = GetCommandLineW(); + if (!cmd_line_tmp) { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + fprintf(stderr, "unable to get current command line: [0x%08lx]: %s\n", err, err_text); + + goto parent_out; + } + + cmd_line_len = wcslen(cmd_line_tmp); + if (cmd_line_len > sizeof(cmd_line) - 1) { + fprintf(stderr, "command line is too long\n"); + goto parent_out; + } + memmove(cmd_line, cmd_line_tmp, (cmd_line_len + 1)*sizeof(wchar_t)); + + job = CreateJobObject(NULL, NULL); + if (!job) { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + fprintf(stderr, "unable to create job object: [0x%08lx]: %s\n", err, err_text); + + goto parent_out; + } + + job_info.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE; + if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &job_info, sizeof(job_info))) { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + fprintf(stderr, "unable to configure job object: [0x%08lx]: %s\n", err, err_text); + } + + while (parent) { + i = kids; + while (0 < i--) { + DWORD status; + + if (NULL != kid_cgi_ps[i]) { + if(!GetExitCodeProcess(kid_cgi_ps[i], &status) || status != STILL_ACTIVE) { + CloseHandle(kid_cgi_ps[i]); + kid_cgi_ps[i] = NULL; + } + } + } + + i = kids; + while (0 < i--) { + PROCESS_INFORMATION pi; + STARTUPINFOW si; + + if (NULL != kid_cgi_ps[i]) { + continue; + } + + ZeroMemory(&si, sizeof(si)); + si.cb = sizeof(si); + ZeroMemory(&pi, sizeof(pi)); + + si.dwFlags = STARTF_USESTDHANDLES; + si.hStdOutput = INVALID_HANDLE_VALUE; + si.hStdInput = (HANDLE)_get_osfhandle(fcgi_fd); + si.hStdError = INVALID_HANDLE_VALUE; + + if (CreateProcessW(NULL, cmd_line, NULL, NULL, TRUE, CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) { + kid_cgi_ps[i] = pi.hProcess; + if (!AssignProcessToJobObject(job, pi.hProcess)) { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + fprintf(stderr, "unable to assign child process to job object: [0x%08lx]: %s\n", err, err_text); + } + CloseHandle(pi.hThread); + } else { + DWORD err = GetLastError(); + char *err_text = php_win32_error_to_msg(err); + + kid_cgi_ps[i] = NULL; + + fprintf(stderr, "unable to spawn: [0x%08lx]: %s\n", err, err_text); + } + } + + WaitForMultipleObjects(kids, kid_cgi_ps, FALSE, INFINITE); + } + + /* restore my env */ + SetEnvironmentVariable("PHP_FCGI_CHILDREN", kid_buf); + + goto parent_out; + } else { + parent = 0; + } #endif /* WIN32 */ } @@ -2584,9 +2746,7 @@ out: #endif } -#ifndef PHP_WIN32 parent_out: -#endif SG(server_context) = NULL; php_module_shutdown(); |