summaryrefslogtreecommitdiff
path: root/threadproc/win32/proc.c
diff options
context:
space:
mode:
Diffstat (limited to 'threadproc/win32/proc.c')
-rw-r--r--threadproc/win32/proc.c384
1 files changed, 384 insertions, 0 deletions
diff --git a/threadproc/win32/proc.c b/threadproc/win32/proc.c
new file mode 100644
index 000000000..50c454a35
--- /dev/null
+++ b/threadproc/win32/proc.c
@@ -0,0 +1,384 @@
+/* ====================================================================
+ * Copyright (c) 1999 The Apache Group. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * 4. The names "Apache Server" and "Apache Group" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * apache@apache.org.
+ *
+ * 5. Products derived from this software may not be called "Apache"
+ * nor may "Apache" appear in their names without prior written
+ * permission of the Apache Group.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the Apache Group
+ * for use in the Apache HTTP server project (http://www.apache.org/)."
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE APACHE GROUP ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE APACHE GROUP OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of the Apache Group.
+ * For more information on the Apache Group and the Apache HTTP server
+ * project, please see <http://www.apache.org/>.
+ *
+ */
+
+#include "threadproc.h"
+#include "fileio.h"
+
+#include "apr_thread_proc.h"
+#include "apr_file_io.h"
+#include "apr_general.h"
+#include "apr_lib.h"
+#include "apr_portable.h"
+#include <stdlib.h>
+#include <signal.h>
+#include <string.h>
+#include <process.h>
+
+ap_status_t ap_createprocattr_init(ap_context_t *cont, struct procattr_t **new)
+{
+ (*new) = (struct procattr_t *)ap_palloc(cont,
+ sizeof(struct procattr_t));
+
+ if ((*new) == NULL) {
+ return APR_ENOMEM;
+ }
+ (*new)->cntxt = cont;
+ (*new)->parent_in = NULL;
+ (*new)->child_in = NULL;
+ (*new)->parent_out = NULL;
+ (*new)->child_out = NULL;
+ (*new)->parent_err = NULL;
+ (*new)->child_err = NULL;
+ (*new)->currdir = NULL;
+ (*new)->cmdtype = APR_PROGRAM;
+ (*new)->detached = TRUE;
+
+ memset(&(*new)->si, 0, sizeof((*new)->si));
+
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_setprocattr_io(struct procattr_t *attr, ap_int32_t in,
+ ap_int32_t out, ap_int32_t err)
+{
+ ap_status_t stat;
+ if (in) {
+ if ((stat = ap_create_pipe(attr->cntxt, &attr->child_in,
+ &attr->parent_in)) != APR_SUCCESS) {
+ return stat;
+ }
+ }
+ if (out) {
+ if ((stat = ap_create_pipe(attr->cntxt, &attr->parent_out,
+ &attr->child_out)) != APR_SUCCESS) {
+ return stat;
+ }
+ }
+ if (err) {
+ if ((stat = ap_create_pipe(attr->cntxt, &attr->parent_err,
+ &attr->child_err)) != APR_SUCCESS) {
+ return stat;
+ }
+ }
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_setprocattr_dir(struct procattr_t *attr,
+ char *dir)
+{
+ attr->currdir = ap_pstrdup(attr->cntxt, dir);
+ if (attr->currdir) {
+ return APR_SUCCESS;
+ }
+ return APR_ENOMEM;
+}
+
+ap_status_t ap_setprocattr_cmdtype(struct procattr_t *attr,
+ ap_cmdtype_e cmd)
+{
+ attr->cmdtype = cmd;
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_setprocattr_detach(struct procattr_t *attr,
+ ap_int32_t det)
+{
+ attr->detached = det;
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_create_process(ap_context_t *cont, char *progname,
+ char *const args[], char **env,
+ struct procattr_t *attr, struct proc_t **new)
+{
+ int i, iEnvBlockLen;
+ char *cmdline;
+ HANDLE hCurrentProcess;
+ HANDLE hParentindup, hParentoutdup,hParenterrdup;
+ char ppid[20];
+ char *envstr;
+ char *pEnvBlock, *pNext;
+
+
+
+ (*new) = (struct proc_t *)ap_palloc(cont, sizeof(struct proc_t));
+
+ if ((*new) == NULL) {
+ return APR_ENOMEM;
+ }
+
+ (*new)->cntxt = cont;
+ (*new)->attr = attr;
+
+ attr->si.cb = sizeof(attr->si);
+ if (attr->detached) {
+ /* If we are creating ourselves detached, Then we should hide the
+ * window we are starting in. And we had better redfine our
+ * handles for STDIN, STDOUT, and STDERR.
+ */
+ attr->si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES;
+ attr->si.wShowWindow = SW_HIDE;
+
+ if (attr->child_in) {
+ attr->si.hStdInput = attr->child_in->filehand;
+ }
+
+ if (attr->child_out) {
+ attr->si.hStdOutput = attr->child_out->filehand;
+ }
+
+ if (attr->child_err) {
+ attr->si.hStdError = attr->child_err->filehand;
+ }
+ }
+
+ cmdline = args[0];
+ i = 1;
+ while (args[i]) {
+ cmdline = ap_pstrcat(cont, cmdline, " ", args[i], NULL);
+ i++;
+ }
+ /*
+ * When the pipe handles are created, the security descriptor
+ * indicates that the handle can be inherited. However, we do not
+ * want the server side handles to the pipe to be inherited by the
+ * child CGI process. If the child CGI does inherit the server
+ * side handles, then the child may be left around if the server
+ * closes its handles (e.g. if the http connection is aborted),
+ * because the child will have a valid copy of handles to both
+ * sides of the pipes, and no I/O error will occur. Microsoft
+ * recommends using DuplicateHandle to turn off the inherit bit
+ * under NT and Win95.
+ */
+ hCurrentProcess = GetCurrentProcess();
+ if ((attr->child_in && !DuplicateHandle(hCurrentProcess, attr->parent_in->filehand,
+ hCurrentProcess,
+ &hParentindup, 0, FALSE,
+ DUPLICATE_SAME_ACCESS))
+ || (attr->child_out && !DuplicateHandle(hCurrentProcess, attr->parent_out->filehand,
+ hCurrentProcess, &hParentoutdup,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))
+ || (attr->child_err && !DuplicateHandle(hCurrentProcess, attr->parent_err->filehand,
+ hCurrentProcess, &hParenterrdup,
+ 0, FALSE, DUPLICATE_SAME_ACCESS))) {
+ if (attr->child_in) {
+ ap_close(attr->child_in);
+ ap_close(attr->parent_in);
+ }
+ if (attr->child_out) {
+ ap_close(attr->child_out);
+ ap_close(attr->parent_out);
+ }
+ if (attr->child_err) {
+ ap_close(attr->child_err);
+ ap_close(attr->parent_err);
+ }
+ return APR_EEXIST;
+ }
+ else {
+ if (attr->child_in) {
+ ap_close(attr->parent_in);
+ attr->parent_in->filehand = hParentindup;
+ }
+ if (attr->child_out) {
+ ap_close(attr->parent_out);
+ attr->parent_out->filehand = hParentoutdup;
+ }
+ if (attr->child_err) {
+ ap_close(attr->parent_err);
+ attr->parent_err->filehand = hParenterrdup;
+ }
+ }
+
+ _itoa(_getpid(), ppid, 10);
+ if (env) {
+
+ envstr = ap_pstrcat(cont, "parentpid=", ppid, NULL);
+ /*
+ * Win32's CreateProcess call requires that the environment
+ * be passed in an environment block, a null terminated block of
+ * null terminated strings.
+ */
+ i = 0;
+ iEnvBlockLen = 1;
+ while (env[i]) {
+ iEnvBlockLen += strlen(env[i]) + 1;
+ i++;
+ }
+
+ pEnvBlock = (char *)ap_pcalloc(cont, iEnvBlockLen + strlen(envstr));
+
+ i = 0;
+ pNext = pEnvBlock;
+ while (env[i]) {
+ strcpy(pNext, env[i]);
+ pNext = pNext + strlen(pNext) + 1;
+ i++;
+ }
+ strcpy(pNext, envstr);
+ }
+ else {
+ SetEnvironmentVariable("parentpid", ppid);
+ pEnvBlock = NULL;
+ }
+
+
+ if (CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, pEnvBlock, attr->currdir,
+ &attr->si, &(*new)->pi)) {
+ if (attr->detached) {
+ CloseHandle((*new)->pi.hProcess);
+ }
+ if (attr->child_in) {
+ ap_close(attr->child_in);
+ }
+ if (attr->child_out) {
+ ap_close(attr->child_out);
+ }
+ if (attr->child_err) {
+ ap_close(attr->child_err);
+ }
+ CloseHandle((*new)->pi.hThread);
+ return APR_SUCCESS;
+ }
+
+ return GetLastError();
+}
+
+ap_status_t ap_get_childin(struct proc_t *proc, ap_file_t **new)
+{
+ (*new) = proc->attr->parent_in;
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_get_childout(struct proc_t *proc, ap_file_t **new)
+{
+ (*new) = proc->attr->parent_out;
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_get_childerr(struct proc_t *proc, ap_file_t **new)
+{
+ (*new) = proc->attr->parent_err;
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_wait_proc(struct proc_t *proc,
+ ap_wait_how_e wait)
+{
+ pid_t stat;
+ if (!proc)
+ return APR_ENOPROC;
+ if (wait == APR_WAIT) {
+ if ((stat = WaitForSingleObject(proc->pi.hProcess, INFINITE)) == WAIT_OBJECT_0) {
+ return APR_CHILD_DONE;
+ }
+ else if (stat == WAIT_TIMEOUT) {
+ return APR_CHILD_NOTDONE;
+ }
+ return APR_EEXIST;
+ }
+ if ((stat = WaitForSingleObject(proc->pi.hProcess, 0)) == WAIT_OBJECT_0) {
+ return APR_CHILD_DONE;
+ }
+ else if (stat == WAIT_TIMEOUT) {
+ return APR_CHILD_NOTDONE;
+ }
+ return APR_EEXIST;
+}
+
+ap_status_t ap_get_procdata(struct proc_t *proc, void *data)
+{
+ if (proc != NULL) {
+ return ap_get_userdata(proc->cntxt, &data);
+ }
+ else {
+ data = NULL;
+ return APR_ENOPROC;
+ }
+}
+
+ap_status_t ap_set_procdata(struct proc_t *proc, void *data)
+{
+ if (proc != NULL) {
+ return ap_set_userdata(proc->cntxt, data);
+ }
+ else {
+ data = NULL;
+ return APR_ENOPROC;
+ }
+}
+
+ap_status_t ap_get_os_proc(ap_proc_t *proc, ap_os_proc_t *theproc)
+{
+ if (proc == NULL) {
+ return APR_ENOPROC;
+ }
+ theproc = &(proc->pi);
+ return APR_SUCCESS;
+}
+
+ap_status_t ap_put_os_proc(ap_context_t *cont, struct proc_t **proc,
+ ap_os_proc_t *theproc)
+{
+ if (cont == NULL) {
+ return APR_ENOCONT;
+ }
+ if ((*proc) == NULL) {
+ (*proc) = (struct proc_t *)ap_palloc(cont, sizeof(struct proc_t));
+ (*proc)->cntxt = cont;
+ }
+ (*proc)->pi = *theproc;
+ return APR_SUCCESS;
+}