/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* * * @author Mladen Turk * @version $Revision: 525491 $, $Date: 2007-04-04 13:19:28 +0200 (Wed, 04 Apr 2007) $ */ #include "tcn.h" #include "apr_thread_proc.h" #include "apr_version.h" #define ERRFN_USERDATA_KEY "TCNATIVECHILDERRFN" static void generic_child_errfn(apr_pool_t *pool, apr_status_t err, const char *description) { void *data; tcn_callback_t *cb; apr_pool_userdata_get(&data, ERRFN_USERDATA_KEY, pool); cb = (tcn_callback_t *)data; if (cb) { JNIEnv *env; tcn_get_java_env(&env); if (!TCN_IS_NULL(env, cb->obj)) { (*(env))->CallVoidMethod(env, cb->obj, cb->mid[0], P2J(pool), (jint)err, (*(env))->NewStringUTF(env, description), NULL); } } } static apr_status_t child_errfn_pool_cleanup(void *data) { tcn_callback_t *cb = (tcn_callback_t *)data; if (data) { JNIEnv *env; tcn_get_java_env(&env); if (!TCN_IS_NULL(env, cb->obj)) { TCN_UNLOAD_CLASS(env, cb->obj); } free(cb); } return APR_SUCCESS; } TCN_IMPLEMENT_CALL(jlong, Procattr, create)(TCN_STDARGS, jlong pool) { apr_pool_t *p = J2P(pool, apr_pool_t *); apr_procattr_t *attr; UNREFERENCED(o); TCN_THROW_IF_ERR(apr_procattr_create(&attr, p), attr); cleanup: return P2J(attr); } TCN_IMPLEMENT_CALL(jint, Procattr, ioSet)(TCN_STDARGS, jlong attr, jint in, jint out, jint err) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_io_set(a, (apr_int32_t)in, (apr_int32_t)out, (apr_int32_t)err); } TCN_IMPLEMENT_CALL(jint, Procattr, childInSet)(TCN_STDARGS, jlong attr, jlong in, jlong parent) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); apr_file_t *f = J2P(in, apr_file_t *); apr_file_t *p = J2P(parent, apr_file_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_child_in_set(a, f, p); } TCN_IMPLEMENT_CALL(jint, Procattr, childOutSet)(TCN_STDARGS, jlong attr, jlong out, jlong parent) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); apr_file_t *f = J2P(out, apr_file_t *); apr_file_t *p = J2P(parent, apr_file_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_child_out_set(a, f, p); } TCN_IMPLEMENT_CALL(jint, Procattr, childErrSet)(TCN_STDARGS, jlong attr, jlong err, jlong parent) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); apr_file_t *f = J2P(err, apr_file_t *); apr_file_t *p = J2P(parent, apr_file_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_child_in_set(a, f, p); } TCN_IMPLEMENT_CALL(jint, Procattr, dirSet)(TCN_STDARGS, jlong attr, jstring dir) { apr_status_t rv; apr_procattr_t *a = J2P(attr, apr_procattr_t *); TCN_ALLOC_CSTRING(dir); UNREFERENCED(o); rv = apr_procattr_dir_set(a, J2S(dir)); TCN_FREE_CSTRING(dir); return (jint) rv; } TCN_IMPLEMENT_CALL(jint, Procattr, cmdtypeSet)(TCN_STDARGS, jlong attr, jint cmd) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_cmdtype_set(a, (apr_int32_t)cmd); } TCN_IMPLEMENT_CALL(jint, Procattr, detachSet)(TCN_STDARGS, jlong attr, jint detach) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_detach_set(a, (apr_int32_t)detach); } TCN_IMPLEMENT_CALL(jint, Procattr, errorCheckSet)(TCN_STDARGS, jlong attr, jint chk) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_error_check_set(a, (apr_int32_t)chk); } TCN_IMPLEMENT_CALL(jint, Procattr, addrspaceSet)(TCN_STDARGS, jlong attr, jint addr) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); UNREFERENCED_STDARGS; return (jint)apr_procattr_addrspace_set(a, (apr_int32_t)addr); } TCN_IMPLEMENT_CALL(jlong, Proc, alloc)(TCN_STDARGS, jlong pool) { apr_pool_t *p = J2P(pool, apr_pool_t *); apr_proc_t *proc; UNREFERENCED_STDARGS; proc = (apr_proc_t *)apr_pcalloc(p, sizeof(apr_proc_t)); return P2J(proc); } #define MAX_ARGS_SIZE 1024 #define MAX_ENV_SIZE 1024 TCN_IMPLEMENT_CALL(jint, Proc, create)(TCN_STDARGS, jlong proc, jstring progname, jobjectArray args, jobjectArray env, jlong attr, jlong pool) { apr_status_t rv; apr_pool_t *p = J2P(pool, apr_pool_t *); apr_procattr_t *a = J2P(attr, apr_procattr_t *); apr_proc_t *np = J2P(proc, apr_proc_t *); TCN_ALLOC_CSTRING(progname); char *s_args[MAX_ARGS_SIZE]; char *s_env[MAX_ENV_SIZE]; const char * const *pargs = NULL; const char * const *penv = NULL; jsize as = 0; jsize es = 0; jsize i; UNREFERENCED(o); if (args) as = (*e)->GetArrayLength(e, args); if (env) es = (*e)->GetArrayLength(e, args); if (as > (MAX_ARGS_SIZE - 1) || es > (MAX_ENV_SIZE - 2)) { TCN_FREE_CSTRING(progname); return APR_EINVAL; } if (as) { for (i = 0; i < as; i++) { jstring str = (*e)->GetObjectArrayElement(e, args, i); s_args[i] = tcn_get_string(e, str); (*e)->DeleteLocalRef(e, str); } s_args[i] = NULL; pargs = (const char * const *)&s_args[0]; } if (es) { for (i = 0; i < es; i++) { jstring str = (*e)->GetObjectArrayElement(e, env, i); s_env[i+1] = tcn_get_string(e, str); (*e)->DeleteLocalRef(e, str); } #ifdef WIN32 s_env[i++] = apr_psprintf(p, TCN_PARENT_IDE "=%d", getpid()); #endif s_env[i] = NULL; penv = (const char * const *)&s_env[0]; } #ifdef WIN32 else { char pps[32]; itoa(getpid(), pps, 10); SetEnvironmentVariable(TCN_PARENT_IDE, pps); } #endif rv = apr_proc_create(np, J2S(progname), pargs, penv, a, p); #ifdef WIN32 if (!es) SetEnvironmentVariable(TCN_PARENT_IDE, NULL); #endif /* Free local resources */ TCN_FREE_CSTRING(progname); for (i = 0; i < as; i++) { if (s_args[i]) free(s_args[i]); } for (i = 0; i < es; i++) { if (s_env[i]) free(s_env[i]); } return rv; } TCN_IMPLEMENT_CALL(jint, Proc, wait)(TCN_STDARGS, jlong proc, jintArray rvals, jint waithow) { apr_status_t rv; apr_proc_t *p = J2P(proc, apr_proc_t *); int exitcode; apr_exit_why_e exitwhy; UNREFERENCED(o); rv = apr_proc_wait(p, &exitcode, &exitwhy, (apr_wait_how_e)waithow); if (rv == APR_SUCCESS && rvals) { jsize n = (*e)->GetArrayLength(e, rvals); if (n > 1) { jint *ints = (*e)->GetIntArrayElements(e, rvals, NULL); ints[0] = exitcode; ints[1] = exitwhy; (*e)->ReleaseIntArrayElements(e, rvals, ints, 0); } } return rv; } TCN_IMPLEMENT_CALL(jint, Proc, waitAllProcs)(TCN_STDARGS, jlong proc, jintArray rvals, jint waithow, jlong pool) { apr_status_t rv; apr_proc_t *p = J2P(proc, apr_proc_t *); apr_pool_t *c = J2P(pool, apr_pool_t *); int exitcode; apr_exit_why_e exitwhy; UNREFERENCED(o); rv = apr_proc_wait_all_procs(p, &exitcode, &exitwhy, (apr_wait_how_e)waithow, c); if (rv == APR_SUCCESS && rvals) { jsize n = (*e)->GetArrayLength(e, rvals); if (n > 1) { jint *ints = (*e)->GetIntArrayElements(e, rvals, NULL); ints[0] = exitcode; ints[1] = exitwhy; (*e)->ReleaseIntArrayElements(e, rvals, ints, 0); } } return rv; } TCN_IMPLEMENT_CALL(jint, Proc, detach)(TCN_STDARGS, jint daemonize) { UNREFERENCED_STDARGS; #if defined(WIN32) || defined (NETWARE) UNREFERENCED(daemonize); return APR_ENOTIMPL; #else return (jint)apr_proc_detach(daemonize); #endif } TCN_IMPLEMENT_CALL(jint, Proc, kill)(TCN_STDARGS, jlong proc, jint sig) { apr_proc_t *p = J2P(proc, apr_proc_t *); UNREFERENCED_STDARGS; return (jint)apr_proc_kill(p, (int)sig); } TCN_IMPLEMENT_CALL(void, Pool, noteSubprocess)(TCN_STDARGS, jlong pool, jlong proc, jint how) { apr_proc_t *p = J2P(proc, apr_proc_t *); apr_pool_t *a = J2P(pool, apr_pool_t *); UNREFERENCED_STDARGS; apr_pool_note_subprocess(a, p, (apr_kill_conditions_e)how); } TCN_IMPLEMENT_CALL(jint, Proc, fork)(TCN_STDARGS, jlongArray proc, jlong pool) { apr_status_t rv = APR_EINVAL; #if APR_HAS_FORK apr_pool_t *p = J2P(pool, apr_pool_t *); apr_proc_t *f = apr_pcalloc(p, sizeof(apr_proc_t)); UNREFERENCED(o); rv = apr_proc_fork(f, p); if (rv == APR_SUCCESS && proc) { jsize n = (*e)->GetArrayLength(e, proc); if (n > 0) { jlong *rp = (*e)->GetLongArrayElements(e, proc, NULL); rp[0] = P2J(f); (*e)->ReleaseLongArrayElements(e, proc, rp, 0); } } #else UNREFERENCED_STDARGS; UNREFERENCED(proc); UNREFERENCED(pool); #endif return rv; } TCN_IMPLEMENT_CALL(void, Procattr, errfnSet)(TCN_STDARGS, jlong attr, jlong pool, jobject obj) { apr_procattr_t *a = J2P(attr, apr_procattr_t *); apr_pool_t *p = J2P(pool, apr_pool_t *); tcn_callback_t *cb = (tcn_callback_t *)malloc(sizeof(tcn_callback_t)); jclass cls; UNREFERENCED(o); if (cb == NULL) { return; } cls = (*e)->GetObjectClass(e, obj); cb->obj = (*e)->NewGlobalRef(e, obj); cb->mid[0] = (*e)->GetMethodID(e, cls, "callback", "(JILjava/lang/String;)V"); apr_pool_userdata_setn(cb, ERRFN_USERDATA_KEY, child_errfn_pool_cleanup, p); apr_procattr_child_errfn_set(a, generic_child_errfn); } TCN_IMPLEMENT_CALL(jint, Procattr, userSet)(TCN_STDARGS, jlong attr, jstring username, jstring password) { #if ((APR_MAJOR_VERSION >= 1) && (APR_MINOR_VERSION >= 1)) apr_status_t rv; apr_procattr_t *a = J2P(attr, apr_procattr_t *); TCN_ALLOC_CSTRING(username); #if APR_PROCATTR_USER_SET_REQUIRES_PASSWORD TCN_ALLOC_CSTRING(password); #else const char *cpassword = NULL; #endif UNREFERENCED(o); rv = apr_procattr_user_set(a, J2S(username), J2S(password)); TCN_FREE_CSTRING(username); #if APR_PROCATTR_USER_SET_REQUIRES_PASSWORD TCN_FREE_CSTRING(password); #endif return (jint) rv; #else UNREFERENCED_STDARGS; UNREFERENCED(attr); UNREFERENCED(username); UNREFERENCED(password); return APR_ENOTIMPL; #endif } TCN_IMPLEMENT_CALL(jint, Procattr, groupSet)(TCN_STDARGS, jlong attr, jstring group) { #if ((APR_MAJOR_VERSION >= 1) && (APR_MINOR_VERSION >= 1)) apr_status_t rv; apr_procattr_t *a = J2P(attr, apr_procattr_t *); TCN_ALLOC_CSTRING(group); UNREFERENCED(o); rv = apr_procattr_group_set(a, J2S(group)); TCN_FREE_CSTRING(group); return (jint) rv; #else UNREFERENCED_STDARGS; UNREFERENCED(attr); UNREFERENCED(group); return APR_ENOTIMPL; #endif }