blob: 7f9376831263d87289f846a2ef73ce60d45c05e1 [file] [log] [blame]
/* 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$, $Date$
*/
#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
}