--- /dev/null
+ Building from the cvs tree:
+ sh buildconf --with-apr=apr_source_location.
+ configure --with-apr=apr_install_location --with-ssl=openssl_install_location
+ make
+
+ Testing the build:
+ The make should produce a .so file named libtcnative-1.so.
+ Build the jar containing the example by
+ cd ..
+ ant jar
+ Run the example:
+ ant example-basic
+
+ Using it in Tomcat:
+ 1 - In <Connector> use of conf/server.xml:
+ protocol="org.apache.coyote.http11.Http11AprProtocol"
+ 2 - In bin/setenv.sh add the following:
+ CATALINA_OPTS="$CATALINA_OPTS -Djava.library.path=tclib_location"
+ In my machine I am using:
+ /home/jfclere/tomcat-connectors/jni/native/.libs for tclib_location
+
+NOTES:
+ - configure --without-ssl : Configure without ssl support.
+ - To use it in Tomcat you may have to add in bin/setenv.sh:
+ LD_LIBRARY_PATH=openssl_install_location/lib; export LD_LIBRARY_PATH
+ (use ldd ./.libs/libtcnative-1.so to check it).
+ - quick testing: openssl s_client -connect localhost:8443
+ - For MAC OS X you must manually add a link
+ cd ${tcnative installdir}
+ ln -d libtcnative-1.dylib libtcnative-1.jnilib
--- /dev/null
+#
+# Top-level Makefile for TCNATIVE
+#
+
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+
+# gets substituted into some targets
+TCNATIVE_MAJOR_VERSION=@TCNATIVE_MAJOR_VERSION@
+TCNATIVE_DOTTED_VERSION=@TCNATIVE_DOTTED_VERSION@
+TCNATIVE_LIBTOOL_VERSION=@TCNATIVE_LIBTOOL_VERSION@
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+# this sucks, but it's the only way to add extra flags to the LT_COMPILE
+INCLUDES = @CFLAGS@ @CPPFLAGS@ @TCNATIVE_INCLUDES@ @TCNATIVE_PRIV_INCLUDES@ @APR_INCLUDES@
+TCNATIVE_LDFLAGS = @TCNATIVE_LDFLAGS@
+TCNATIVE_LIBS = @TCNATIVE_LIBS@
+
+TARGET_LIB = lib@TCNATIVE_LIBNAME@.la
+EXTRA_OS_LINK=@EXTRA_OS_LINK@
+TCNATIVE_PCFILE = tcnative-$(TCNATIVE_MAJOR_VERSION).pc
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+
+TARGETS = $(TARGET_LIB)
+
+# bring in rules.mk for standard functionality
+@INCLUDE_RULES@
+@INCLUDE_OUTPUTS@
+
+LINK = $(LIBTOOL) $(LTFLAGS) --mode=link $(LT_LDFLAGS) $(COMPILE) -version-info $(TCNATIVE_LIBTOOL_VERSION) $(ALL_LDFLAGS) -o $@
+CLEAN_SUBDIRS = test
+
+CLEAN_TARGETS = .make.dirs
+DISTCLEAN_TARGETS = config.cache config.log config.status libtool \
+ build/rules.mk tcnative.pc
+EXTRACLEAN_TARGETS = configure aclocal.m4 build-outputs.mk \
+ build/apr_common.m4 build/find_apr.m4 build/install.sh \
+ build/config.guess build/config.sub tcnative.spec
+
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+bindir=@bindir@
+libdir=@libdir@
+includedir=@includedir@
+top_srcdir=@abs_srcdir@
+top_blddir=@abs_builddir@
+
+
+install: $(TARGET_LIB)
+ $(APR_MKDIR) $(DESTDIR)$(includedir) $(DESTDIR)$(libdir)/pkgconfig \
+ $(DESTDIR)$(libdir) $(DESTDIR)$(bindir)
+ $(INSTALL_DATA) tcnative.pc $(DESTDIR)$(libdir)/pkgconfig/$(TCNATIVE_PCFILE)
+ list='$(INSTALL_SUBDIRS)'; for i in $$list; do \
+ ( cd $$i ; $(MAKE) DESTDIR=$(DESTDIR) install ); \
+ done
+ $(LIBTOOL) --mode=install $(INSTALL) -m 755 $(TARGET_LIB) $(DESTDIR)$(libdir)
+
+$(TARGET_LIB): $(OBJECTS)
+ $(LINK) @lib_target@ @TCNATIVE_LDFLAGS@ @TCNATIVE_LIBS@ @SSL_LIBS@
+
+check: $(TARGET_LIB)
+ (cd test && $(MAKE) check)
--- /dev/null
+#
+# Configuration file for APRJAVA. Used by APR/build/gen-build.py
+#
+
+[options]
+
+# the platform-independent .c files
+paths =
+ src/*.c
+
+# we have no platform-specific subdirs
+platform_dirs =
+ os
+
+# the public headers
+headers = include/*.h
+
+# we have a recursive makefile for the test files (for now)
+# test/*.c
--- /dev/null
+#! /bin/sh
+
+echo "buildconf: checking installation..."
+
+# any python
+python=`build/PrintPath python`
+if test -z "$python"; then
+echo "buildconf: python not found."
+echo " You need python installed"
+echo " to build APR from CVS."
+exit 1
+else
+py_version=`python -c 'import sys; print sys.version' 2>&1|sed 's/ .*//;q'`
+echo "buildconf: python version $py_version (ok)"
+fi
+
+# autoconf 2.13 or newer
+ac_version=`${AUTOCONF:-autoconf} --version 2>/dev/null|sed -e 's/^[^0-9]*//;s/[a-z]* *$//;q'`
+if test -z "$ac_version"; then
+echo "buildconf: autoconf not found."
+echo " You need autoconf version 2.13 or newer installed"
+echo " to build Apache from CVS."
+exit 1
+fi
+IFS=.; set $ac_version; IFS=' '
+if test "$1" = "2" -a "$2" -lt "13" || test "$1" -lt "2"; then
+echo "buildconf: autoconf version $ac_version found."
+echo " You need autoconf version 2.13 or newer installed"
+echo " to build Apache from CVS."
+exit 1
+else
+echo "buildconf: autoconf version $ac_version (ok)"
+fi
+
+# Sample libtool --version outputs:
+# ltmain.sh (GNU libtool) 1.3.3 (1.385.2.181 1999/07/02 15:49:11)
+# ltmain.sh (GNU libtool 1.1361 2004/01/02 23:10:52) 1.5a
+# output is multiline from 1.5 onwards
+
+# Require libtool 1.3.3 or newer
+libtool=`build/PrintPath glibtool libtool libtool15 libtool14`
+lt_pversion=`$libtool --version 2>/dev/null|sed -e 's/([^)]*)//g;s/^[^0-9]*//;s/[- ].*//g;q'`
+if test -z "$lt_pversion"; then
+echo "buildconf: libtool not found."
+echo " You need libtool version 1.3.3 or newer installed"
+echo " to build Apache from CVS."
+exit 1
+fi
+lt_version=`echo $lt_pversion|sed -e 's/\([a-z]*\)$/.\1/'`
+IFS=.; set $lt_version; IFS=' '
+lt_status="good"
+if test "$1" = "1"; then
+ if test "$2" -lt "3"; then
+ lt_status="bad"
+ else
+ if test "$2" = "3"; then
+ if test -z "$3" -o "$3" = "1" -o "$3" = "2"; then
+ lt_status="bad"
+ fi
+ fi
+ fi
+fi
+if test $lt_status = "good"; then
+ echo "buildconf: libtool version $lt_pversion (ok)"
+ exit 0
+fi
+
+echo "buildconf: libtool version $lt_pversion found."
+echo " You need libtool version 1.3.3 or newer installed"
+echo " to build Apache from CVS."
+
+exit 1
--- /dev/null
+#!/bin/sh
+#
+# extract version numbers from a header file
+#
+# USAGE: get-version.sh CMD VERSION_HEADER PREFIX
+# where CMD is one of: all, major, libtool
+# where PREFIX is the prefix to {MAJOR|MINOR|PATCH}_VERSION defines
+#
+# get-version.sh all returns a dotted version number
+# get-version.sh major returns just the major version number
+# get-version.sh libtool returns a version "libtool -version-info" format
+#
+
+if test $# != 3; then
+ echo "USAGE: $0 CMD VERSION_HEADER PREFIX"
+ echo " where CMD is one of: all, major, libtool"
+ exit 1
+fi
+
+major_sed="/#define.*$3_MAJOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+minor_sed="/#define.*$3_MINOR_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+patch_sed="/#define.*$3_PATCH_VERSION/s/^[^0-9]*\([0-9]*\).*$/\1/p"
+major="`sed -n $major_sed $2`"
+minor="`sed -n $minor_sed $2`"
+patch="`sed -n $patch_sed $2`"
+
+if test "$1" = "all"; then
+ echo ${major}.${minor}.${patch}
+elif test "$1" = "major"; then
+ echo ${major}
+elif test "$1" = "libtool"; then
+ # Yes, ${minor}:${patch}:${minor} is correct due to libtool idiocy.
+ echo ${minor}:${patch}:${minor}
+else
+ echo "ERROR: unknown version CMD ($1)"
+ exit 1
+fi
--- /dev/null
+#!/usr/local/bin/perl
+#
+# Heuristically converts line endings to the current OS's preferred format
+#
+# All existing line endings must be identical (e.g. lf's only, or even
+# the accedental cr.cr.lf sequence.) If some lines end lf, and others as
+# cr.lf, the file is presumed binary. If the cr character appears anywhere
+# except prefixed to an lf, the file is presumed binary. If there is no
+# change in the resulting file size, or the file is binary, the conversion
+# is discarded.
+#
+# Todo: Handle NULL stdin characters gracefully.
+#
+
+use IO::File;
+use File::Find;
+
+# The ignore list is '-' seperated, with this leading hyphen and
+# trailing hyphens in ever concatinated list below.
+$ignore = "-";
+
+# Image formats
+$ignore .= "gif-jpg-jpeg-png-ico-bmp-";
+
+# Archive formats
+$ignore .= "tar-gz-z-zip-jar-war-";
+
+# Many document formats
+$ignore .= "eps-psd-pdf-ai-";
+
+# Some encodings
+$ignore .= "ucs2-ucs4-";
+
+# Some binary objects
+$ignore .= "class-so-dll-exe-obj-";
+
+# Some build env files in NW/Win32
+$ignore .= "mcp-xdc-ncb-opt-pdb-ilk-sbr-";
+
+$preservedate = 1;
+
+$forceending = 0;
+
+$givenpaths = 0;
+
+$notnative = 0;
+
+while (defined @ARGV[0]) {
+ if (@ARGV[0] eq '--touch') {
+ $preservedate = 0;
+ }
+ elsif (@ARGV[0] eq '--nocr') {
+ $notnative = -1;
+ }
+ elsif (@ARGV[0] eq '--cr') {
+ $notnative = 1;
+ }
+ elsif (@ARGV[0] eq '--force') {
+ $forceending = 1;
+ }
+ elsif (@ARGV[0] eq '--FORCE') {
+ $forceending = 2;
+ }
+ elsif (@ARGV[0] =~ m/^-/) {
+ die "What is " . @ARGV[0] . " supposed to mean?\n\n"
+ . "Syntax:\t$0 [option()s] [path(s)]\n\n" . <<'OUTCH'
+Where: paths specifies the top level directory to convert (default of '.')
+ options are;
+
+ --cr keep/add one ^M
+ --nocr remove ^M's
+ --touch the datestamp (default: keeps date/attribs)
+ --force mismatched corrections (unbalanced ^M's)
+ --FORCE all files regardless of file name!
+
+OUTCH
+ }
+ else {
+ find(\&totxt, @ARGV[0]);
+ print "scanned " . @ARGV[0] . "\n";
+ $givenpaths = 1;
+ }
+ shift @ARGV;
+}
+
+if (!$givenpaths) {
+ find(\&totxt, '.');
+ print "did .\n";
+}
+
+sub totxt {
+ $oname = $_;
+ $tname = '.#' . $_;
+ if (!-f) {
+ return;
+ }
+ @exts = split /\./;
+ if ($forceending < 2) {
+ while ($#exts && ($ext = pop(@exts))) {
+ if ($ignore =~ m|-$ext-|i) {
+ return;
+ }
+ }
+ }
+ @ostat = stat($oname);
+ $srcfl = new IO::File $oname, "r" or die;
+ $dstfl = new IO::File $tname, "w" or die;
+ binmode $srcfl;
+ if ($notnative) {
+ binmode $dstfl;
+ }
+ undef $t;
+ while (<$srcfl>) {
+ if (s/(\r*)\n$/\n/) {
+ $n = length $1;
+ if (!defined $t) {
+ $t = $n;
+ }
+ if (!$forceending && (($n != $t) || m/\r/)) {
+ print "mismatch in " .$oname. ":" .$n. " expected " .$t. "\n";
+ undef $t;
+ last;
+ }
+ elsif ($notnative > 0) {
+ s/\n$/\r\n/;
+ }
+ }
+ print $dstfl $_;
+ }
+ if (defined $t && (tell $srcfl == tell $dstfl)) {
+ undef $t;
+ }
+ undef $srcfl;
+ undef $dstfl;
+ if (defined $t) {
+ unlink $oname or die;
+ rename $tname, $oname or die;
+ @anames = ($oname);
+ if ($preservedate) {
+ utime $ostat[9], $ostat[9], @anames;
+ }
+ chmod $ostat[2] & 07777, @anames;
+ chown $ostat[5], $ostat[6], @anames;
+ print "Converted file " . $oname . " to text in " . $File::Find::dir . "\n";
+ }
+ else {
+ unlink $tname or die;
+ }
+}
--- /dev/null
+#!/bin/sh
+##
+## mkdir.sh -- make directory hierarchy
+##
+## Based on `mkinstalldirs' from Noah Friedman <friedman@prep.ai.mit.edu>
+## as of 1994-03-25, which was placed in the Public Domain.
+## Cleaned up for Apache's Autoconf-style Interface (APACI)
+## by Ralf S. Engelschall <rse@apache.org>
+##
+#
+# This script falls under the Apache License.
+# See http://www.apache.org/docs/LICENSE
+
+
+umask 022
+errstatus=0
+for file in ${1+"$@"} ; do
+ set fnord `echo ":$file" |\
+ sed -e 's/^:\//%/' -e 's/^://' -e 's/\// /g' -e 's/^%/\//'`
+ shift
+ pathcomp=
+ for d in ${1+"$@"}; do
+ pathcomp="$pathcomp$d"
+ case "$pathcomp" in
+ -* ) pathcomp=./$pathcomp ;;
+ ?: ) pathcomp="$pathcomp/"
+ continue ;;
+ esac
+ if test ! -d "$pathcomp"; then
+ echo "mkdir $pathcomp" 1>&2
+ mkdir "$pathcomp" || errstatus=$?
+ fi
+ pathcomp="$pathcomp/"
+ done
+done
+exit $errstatus
+
--- /dev/null
+
+%define tcnver 1
+
+Summary: Tomcat Native Java library
+Name: tcnative
+Version: TCN_VERSION
+Release: TCN_RELEASE
+License: Apache Software License
+Group: System Environment/Libraries
+URL: http://apr.apache.org/
+Source0: %{name}-%{version}.tar.gz
+BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-buildroot
+BuildPrereq: autoconf, libtool, doxygen, apr-devel >= 0:{version}-{release}, openssl >= 0.9.7
+
+%description
+The mission of the Tomcat Native Library (TCN) is to provide a
+free library of C data structures and routines. This library
+contains additional utility interfaces for Java.
+
+%package devel
+Group: Development/Libraries
+Summary: Tomcat Native development kit
+Requires: tcnative = %{version}-%{release}, apr-devel >= 0:{version}-{release}, openssl-devel >= 0.9.7
+
+%description devel
+The mission of the Tomcat Native Library (TCN) is to provide a
+free library of C data structures and routines. This library
+contains additional utility interfaces for Java.
+
+%prep
+%setup -q
+
+%build
+%configure --with-apr=%{_prefix} \
+ --includedir=%{_includedir}/apr-%{tcnver}
+make %{?_smp_mflags} && make dox
+
+%check
+# Run non-interactive tests
+pushd test
+make %{?_smp_mflags} testall CFLAGS=-fno-strict-aliasing
+./testall -v || exit 1
+popd
+
+%install
+rm -rf $RPM_BUILD_ROOT
+make install DESTDIR=$RPM_BUILD_ROOT
+
+# Documentation
+mv docs/dox/html html
+
+# Unpackaged files
+rm -f $RPM_BUILD_ROOT%{_libdir}/tcnative.exp
+
+%clean
+rm -rf $RPM_BUILD_ROOT
+
+%post -p /sbin/ldconfig
+
+%postun -p /sbin/ldconfig
+
+%files
+%defattr(-,root,root,-)
+%doc CHANGES LICENSE NOTICE
+%{_libdir}/libtcnative-%{tcnver}.so.*
+
+%files devel
+%defattr(-,root,root,-)
+%{_libdir}/libtcnative-%{tcnver}.*a
+%{_libdir}/libtcnative-%{tcnver}.so
+%{_libdir}/pkgconfig/tcnative-%{tcnver}.pc
+%{_includedir}/apr-%{tcnver}/*.h
+%doc --parents html
+
+%changelog
+* Tue Jun 22 2004 Mladen Turk <mturk@jboss.com> 1.0.0-1
+- update to support v1.0.2 of APR
+
--- /dev/null
+dnl
+dnl TCN_FIND_APR: figure out where APR is located
+dnl
+AC_DEFUN(TCN_FIND_APR,[
+
+ dnl use the find_apr.m4 script to locate APR. sets apr_found and apr_config
+ APR_FIND_APR(,,,[1])
+ if test "$apr_found" = "no"; then
+ AC_MSG_ERROR(APR could not be located. Please use the --with-apr option.)
+ fi
+
+ APR_BUILD_DIR="`$apr_config --installbuilddir`"
+
+ dnl make APR_BUILD_DIR an absolute directory (we'll need it in the
+ dnl sub-projects in some cases)
+ APR_BUILD_DIR="`cd $APR_BUILD_DIR && pwd`"
+
+ APR_INCLUDES="`$apr_config --includes`"
+ APR_LIBS="`$apr_config --link-libtool --libs`"
+ APR_SO_EXT="`$apr_config --apr-so-ext`"
+ APR_LIB_TARGET="`$apr_config --apr-lib-target`"
+
+ AC_SUBST(APR_INCLUDES)
+ AC_SUBST(APR_LIBS)
+ AC_SUBST(APR_BUILD_DIR)
+])
+
+dnl --------------------------------------------------------------------------
+dnl TCN_JDK
+dnl
+dnl Detection of JDK location and Java Platform (1.2, 1.3, 1.4, 1.5, 1.6)
+dnl result goes in JAVA_HOME / JAVA_PLATFORM (2 -> 1.2 and higher)
+dnl
+dnl --------------------------------------------------------------------------
+AC_DEFUN(
+ [TCN_FIND_JDK],
+ [
+ tempval=""
+ AC_MSG_CHECKING([for JDK location (please wait)])
+ if test -n "${JAVA_HOME}" ; then
+ JAVA_HOME_ENV="${JAVA_HOME}"
+ else
+ JAVA_HOME_ENV=""
+ fi
+
+ JAVA_HOME=""
+ JAVA_PLATFORM=""
+
+ AC_ARG_WITH(
+ [java-home],
+ [ --with-java-home=DIR Location of JDK directory.],
+ [
+
+ # This stuff works if the command line parameter --with-java-home was
+ # specified, so it takes priority rightfully.
+
+ tempval=${withval}
+
+ if test ! -d "${tempval}" ; then
+ AC_MSG_ERROR(Not a directory: ${tempval})
+ fi
+
+ JAVA_HOME=${tempval}
+ AC_MSG_RESULT(${JAVA_HOME})
+ ],
+ [
+ # This works if the parameter was NOT specified, so it's a good time
+ # to see what the enviroment says.
+ # Since Sun uses JAVA_HOME a lot, we check it first and ignore the
+ # JAVA_HOME, otherwise just use whatever JAVA_HOME was specified.
+
+ if test -n "${JAVA_HOME_ENV}" ; then
+ JAVA_HOME=${JAVA_HOME_ENV}
+ AC_MSG_RESULT(${JAVA_HOME_ENV} from environment)
+ fi
+ ])
+
+ if test -z "${JAVA_HOME}" ; then
+
+ # Oh well, nobody set neither JAVA_HOME nor JAVA_HOME, have to guess
+ # The following code is based on the code submitted by Henner Zeller
+ # for ${srcdir}/src/scripts/package/rpm/ApacheJServ.spec
+ # Two variables will be set as a result:
+ #
+ # JAVA_HOME
+ # JAVA_PLATFORM
+ AC_MSG_CHECKING([Try to guess JDK location])
+
+ for JAVA_PREFIX in /usr/local /usr/local/lib /usr /usr/lib /opt /usr/java ; do
+
+ for JAVA_PLATFORM in 6 5 4 3 2 ; do
+
+ for subversion in .9 .8 .7 .6 .5 .4 .3 .2 .1 "" ; do
+
+ for VARIANT in IBMJava2- java java- jdk jdk-; do
+ GUESS="${JAVA_PREFIX}/${VARIANT}1.${JAVA_PLATFORM}${subversion}"
+dnl AC_MSG_CHECKING([${GUESS}])
+ if test -d "${GUESS}/bin" & test -d "${GUESS}/include" ; then
+ JAVA_HOME="${GUESS}"
+ AC_MSG_RESULT([${GUESS}])
+ break
+ fi
+ done
+
+ if test -n "${JAVA_HOME}" ; then
+ break;
+ fi
+
+ done
+
+ if test -n "${JAVA_HOME}" ; then
+ break;
+ fi
+
+ done
+
+ if test -n "${JAVA_HOME}" ; then
+ break;
+ fi
+
+ done
+
+ if test ! -n "${JAVA_HOME}" ; then
+ AC_MSG_ERROR(can't locate a valid JDK location)
+ fi
+
+ fi
+
+ if test -n "${JAVA_PLATFORM}"; then
+ AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM})
+ else
+ AC_MSG_CHECKING(Java platform)
+ fi
+
+ AC_ARG_WITH(java-platform,
+ [ --with-java-platform[=2] Force the Java platorm
+ (value is 1 for 1.1.x or 2 for 1.2.x or greater)],
+ [
+ case "${withval}" in
+ "1"|"2")
+ JAVA_PLATFORM=${withval}
+ ;;
+ *)
+ AC_MSG_ERROR(invalid java platform provided)
+ ;;
+ esac
+ ],
+ [
+ if test -n "${JAVA_PLATFORM}"; then
+ AC_MSG_RESULT(Java Platform detected - 1.${JAVA_PLATFORM})
+ else
+ AC_MSG_CHECKING(Java platform)
+ fi
+ ])
+
+ AC_MSG_RESULT(${JAVA_PLATFORM})
+
+ unset tempval
+ ])
+
+
+AC_DEFUN(
+ [TCN_FIND_JDK_OS],
+ [
+ tempval=""
+ JAVA_OS=""
+ AC_ARG_WITH(os-type,
+ [ --with-os-type[=SUBDIR] Location of JDK os-type subdirectory.],
+ [
+ tempval=${withval}
+
+ if test ! -d "${JAVA_HOME}/${tempval}" ; then
+ AC_MSG_ERROR(Not a directory: ${JAVA_HOME}/${tempval})
+ fi
+
+ JAVA_OS = ${tempval}
+ ],
+ [
+ AC_MSG_CHECKING(os_type directory)
+ JAVA_OS=NONE
+ if test -f ${JAVA_HOME}/${JAVA_INC}/jni_md.h; then
+ JAVA_OS=""
+ else
+ for f in ${JAVA_HOME}/${JAVA_INC}/*/jni_md.h; do
+ if test -f $f; then
+ JAVA_OS=`dirname ${f}`
+ JAVA_OS=`basename ${JAVA_OS}`
+ echo " ${JAVA_OS}"
+ fi
+ done
+ if test "${JAVA_OS}" = "NONE"; then
+ AC_MSG_RESULT(Cannot find jni_md.h in ${JAVA_HOME}/${OS})
+ AC_MSG_ERROR(You should retry --with-os-type=SUBDIR)
+ fi
+ fi
+ ])
+ ])
+
+dnl check for sableVM
+dnl (copied from daemon/src/native/unix/support/apjava.m4)
+AC_DEFUN(
+ [TCN_SABLEVM],
+ [
+ if test x"$JAVA_HOME" != x
+ then
+ AC_PATH_PROG(SABLEVM,sablevm,NONE,$JAVA_HOME/bin)
+ if test "$SABLEVM" != "NONE"
+ then
+ AC_MSG_RESULT([Using sableVM: $SABLEVM])
+ CFLAGS="$CFLAGS -DHAVE_SABLEVM"
+ fi
+ fi
+ ])
+
+dnl TCN_HELP_STRING(LHS, RHS)
+dnl Autoconf 2.50 can not handle substr correctly. It does have
+dnl AC_HELP_STRING, so let's try to call it if we can.
+dnl Note: this define must be on one line so that it can be properly returned
+dnl as the help string.
+AC_DEFUN(TCN_HELP_STRING,[ifelse(regexp(AC_ACVERSION, 2\.1), -1, AC_HELP_STRING($1,$2),[ ]$1 substr([ ],len($1))$2)])dnl
+
+dnl
+dnl TCN_CHECK_SSL_TOOLKIT
+dnl
+dnl Configure for the detected openssl toolkit installation, giving
+dnl preference to "--with-ssl=<path>" if it was specified.
+dnl
+AC_DEFUN(TCN_CHECK_SSL_TOOLKIT,[
+ dnl initialise the variables we use
+ tcn_ssltk_base=""
+ tcn_ssltk_inc=""
+ tcn_ssltk_lib=""
+ tcn_ssltk_type=""
+ AC_ARG_WITH(ssl, TCN_HELP_STRING(--with-ssl=DIR,OpenSSL SSL/TLS toolkit), [
+ dnl If --with-ssl specifies a directory, we use that directory or fail
+ if test "x$withval" != "xyes" -a "x$withval" != "x"; then
+ dnl This ensures $withval is actually a directory and that it is absolute
+ tcn_ssltk_base="`cd $withval ; pwd`"
+ fi
+ ])
+ if test "x$tcn_ssltk_base" = "x"; then
+ AC_MSG_RESULT(none)
+ else
+ AC_MSG_RESULT($tcn_ssltk_base)
+ fi
+
+ dnl Run header and version checks
+ saved_CPPFLAGS=$CPPFLAGS
+ if test "x$tcn_ssltk_base" != "x"; then
+ tcn_ssltk_inc="-I$tcn_ssltk_base/include"
+ CPPFLAGS="$CPPFLAGS $tcn_ssltk_inc"
+ fi
+
+ if test "x$tcn_ssltk_type" = "x"; then
+ AC_MSG_CHECKING(for OpenSSL version)
+ dnl First check for manditory headers
+ AC_CHECK_HEADERS([openssl/opensslv.h], [tcn_ssltk_type="openssl"], [])
+ if test "$tcn_ssltk_type" = "openssl"; then
+ dnl so it's OpenSSL - test for a good version
+ AC_TRY_COMPILE([#include <openssl/opensslv.h>],[
+#if !defined(OPENSSL_VERSION_NUMBER)
+ #error "Missing openssl version"
+#endif
+#if (OPENSSL_VERSION_NUMBER < 0x0090701f)
+ #error "Unsuported openssl version " OPENSSL_VERSION_TEXT
+#endif],
+ [AC_MSG_RESULT(OK)],
+ [dnl Unsuported OpenSSL version
+ AC_MSG_ERROR([Unsupported OpenSSL version. Use 0.9.7a or higher version])
+ ])
+ dnl Look for additional, possibly missing headers
+ AC_CHECK_HEADERS(openssl/engine.h)
+ if test -n "$PKGCONFIG"; then
+ $PKGCONFIG openssl
+ if test $? -eq 0; then
+ tcn_ssltk_inc="$tcn_ssltk_inc `$PKGCONFIG --cflags-only-I openssl`"
+ CPPFLAGS="$CPPFLAGS $tcn_ssltk_inc"
+ fi
+ fi
+ else
+ AC_MSG_RESULT([no OpenSSL headers found])
+ fi
+ fi
+ if test "$tcn_ssltk_type" != "openssl"; then
+ AC_MSG_ERROR([... No OpenSSL headers found])
+ fi
+ dnl restore
+ CPPFLAGS=$saved_CPPFLAGS
+ if test "x$tcn_ssltk_type" = "x"; then
+ AC_MSG_ERROR([...No recognized SSL/TLS toolkit detected])
+ fi
+
+ dnl Run library and function checks
+ saved_LDFLAGS=$LDFLAGS
+ saved_LIBS=$LIBS
+ if test "x$tcn_ssltk_base" != "x"; then
+ if test -d "$tcn_ssltk_base/lib64"; then
+ tcn_ssltk_lib="$tcn_ssltk_base/lib64"
+ elif test -d "$tcn_ssltk_base/lib"; then
+ tcn_ssltk_lib="$tcn_ssltk_base/lib"
+ else
+ tcn_ssltk_lib="$tcn_ssltk_base"
+ fi
+ LDFLAGS="$LDFLAGS -L$tcn_ssltk_lib"
+ fi
+ dnl make sure "other" flags are available so libcrypto and libssl can link
+ LIBS="$LIBS `$apr_config --libs`"
+ liberrors=""
+ if test "$tcn_ssltk_type" = "openssl"; then
+ AC_CHECK_LIB(crypto, SSLeay_version, [], [liberrors="yes"])
+ AC_CHECK_LIB(ssl, SSL_CTX_new, [], [liberrors="yes"])
+ AC_CHECK_FUNCS(ENGINE_init)
+ AC_CHECK_FUNCS(ENGINE_load_builtin_engines)
+ else
+ AC_CHECK_LIB(sslc, SSLC_library_version, [], [liberrors="yes"])
+ AC_CHECK_LIB(sslc, SSL_CTX_new, [], [liberrors="yes"])
+ AC_CHECK_FUNCS(SSL_set_state)
+ fi
+ AC_CHECK_FUNCS(SSL_set_cert_store)
+ dnl restore
+ LDFLAGS=$saved_LDFLAGS
+ LIBS=$saved_LIBS
+ if test "x$liberrors" != "x"; then
+ AC_MSG_ERROR([... Error, SSL/TLS libraries were missing or unusable])
+ fi
+
+ dnl (b) hook up include paths
+ if test "x$tcn_ssltk_inc" != "x"; then
+ APR_ADDTO(TCNATIVE_PRIV_INCLUDES, [$tcn_ssltk_inc])
+ fi
+ dnl (c) hook up linker paths
+ if test "x$tcn_ssltk_lib" != "x"; then
+ APR_ADDTO(TCNATIVE_LDFLAGS, ["-L$tcn_ssltk_lib"])
+ fi
+
+ dnl Adjust configuration based on what we found above.
+ dnl (a) define preprocessor symbols
+ if test "$tcn_ssltk_type" = "openssl"; then
+ APR_SETVAR(SSL_LIBS, [-lssl -lcrypto])
+ APR_ADDTO(CFLAGS, [-DHAVE_OPENSSL])
+ fi
+ AC_SUBST(SSL_LIBS)
+])
--- /dev/null
+#!/bin/sh
+#
+# Copyright 1999-2004 The Apache Software Foundation
+#
+# Licensed 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.
+#
+#
+
+# Default place to look for apr source. Can be overridden with
+# --with-apr=[directory]
+apr_src_dir=../apr
+
+while test $# -gt 0
+do
+ # Normalize
+ case "$1" in
+ -*=*) optarg=`echo "$1" | sed 's/[-_a-zA-Z0-9]*=//'` ;;
+ *) optarg= ;;
+ esac
+
+ case "$1" in
+ --with-apr=*)
+ apr_src_dir=$optarg
+ ;;
+ esac
+
+ shift
+done
+
+if test -d "$apr_src_dir"
+then
+ echo ""
+ echo "Looking for apr source in $apr_src_dir"
+else
+ echo ""
+ echo "Problem finding apr source in $apr_src_dir."
+ echo "Use:"
+ echo " --with-apr=[directory]"
+ exit 1
+fi
+
+# Remove some files, then copy them from apr source tree
+rm -f build/apr_common.m4 build/find_apr.m4 build/install.sh \
+ build/config.guess build/config.sub
+cp $apr_src_dir/build/apr_common.m4 $apr_src_dir/build/find_apr.m4 \
+ $apr_src_dir/build/install.sh $apr_src_dir/build/config.guess \
+ $apr_src_dir/build/config.sub build
+
+# Remove aclocal.m4 as it'll break some builds...
+rm -rf aclocal.m4 autom4te*.cache
+
+echo "Creating configure ..."
+### do some work to toss config.cache?
+if ${AUTOCONF:-autoconf}; then
+ :
+else
+ echo "autoconf failed"
+ exit 1
+fi
+
+#
+# Generate build-outputs.mk for the build systme
+#
+echo "Generating 'make' outputs ..."
+$apr_src_dir/build/gen-build.py make
+
+# Remove autoconf cache again
+rm -rf autom4te*.cache
+
+# Create RPM Spec file
+if [ -f `which cut` ]; then
+ echo rebuilding rpm spec file
+ ( REVISION=`build/get-version.sh all include/tcn_version.h TCN`
+ VERSION=`echo $REVISION | cut -d- -s -f1`
+ RELEASE=`echo $REVISION | cut -d- -s -f2`
+ if [ "x$VERSION" = "x" ]; then
+ VERSION=$REVISION
+ RELEASE=1
+ fi
+ cat ./build/rpm/tcnative.spec.in | \
+ sed -e "s/TCN_VERSION/$VERSION/" \
+ -e "s/TCN_RELEASE/$RELEASE/" \
+ > tcnative.spec )
+fi
+
--- /dev/null
+##
+## config.layout -- Pre-defined Installation Path Layouts
+##
+## Hints:
+## - layouts can be loaded with configure's --enable-layout=ID option
+## - when no --enable-layout option is given, the default layout is `apr'
+## - a trailing plus character (`+') on paths is replaced with a
+## `/<target>' suffix where <target> is currently hardcoded to 'apr'.
+## (This may become a configurable parameter at some point.)
+##
+
+# Generic path layout that needs --prefix=/some/path
+<Layout generic>
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/modules
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+ localstatedir: ${prefix}
+ libsuffix: -${TCNATIVE_MAJOR_VERSION}
+</Layout>
+
+# Classical Tomcat Native path layout designed for parallel installs.
+<Layout tcnative>
+ prefix: /usr/local/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/modules
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+ localstatedir: ${prefix}
+ libsuffix: -${TCNATIVE_MAJOR_VERSION}
+</Layout>
+
+# Classical single-installation APR path layout.
+<Layout classic>
+ prefix: /usr/local/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/modules
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include
+ localstatedir: ${prefix}
+</Layout>
+
+# GNU standards conforming path layout.
+# See FSF's GNU project `make-stds' document for details.
+<Layout GNU>
+ prefix: /usr/local
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/etc+
+ datadir: ${prefix}/share+
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include+
+ localstatedir: ${prefix}/var+
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# Mac OS X Server (Rhapsody)
+<Layout Mac OS X Server>
+ prefix: /Local/Library/WebServer
+ exec_prefix: /usr
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: /System/Library/apr/Modules
+ mandir: ${exec_prefix}/share/man
+ sysconfdir: ${prefix}/Configuration
+ datadir: ${prefix}
+ installbuilddir: /System/Library/apr/Build
+ includedir: /System/Library/Frameworks/apr.framework/Versions/2.0/Headers
+ localstatedir: /var
+ runtimedir: ${prefix}/Logs
+</Layout>
+
+# Darwin/Mac OS Layout
+<Layout Darwin>
+ prefix: /usr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec+
+ mandir: ${prefix}/share/man
+ datadir: /Library/WebServer
+ sysconfdir: /etc+
+ installbuilddir: ${prefix}/share/httpd/build
+ includedir: ${prefix}/include+
+ localstatedir: /var
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# Red Hat Linux 7.x layout
+<Layout RedHat>
+ prefix: /usr
+ exec_prefix: ${prefix}
+ bindir: ${prefix}/bin
+ sbindir: ${prefix}/sbin
+ libdir: ${prefix}/lib
+ libexecdir: ${prefix}/lib/apr
+ mandir: ${prefix}/man
+ sysconfdir: /etc/httpd/conf
+ datadir: /var/www
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include/apr
+ localstatedir: /var
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# According to the /opt filesystem conventions
+<Layout opt>
+ prefix: /opt/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${prefix}/man
+ sysconfdir: /etc${prefix}
+ datadir: ${prefix}/share
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include
+ localstatedir: /var${prefix}
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# BeOS layout...
+<Layout beos>
+ prefix: /boot/home/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include
+ localstatedir: ${prefix}
+ runtimedir: ${localstatedir}/logs
+</Layout>
+
+# SuSE 6.x layout
+<Layout SuSE>
+ prefix: /usr
+ exec_prefix: ${prefix}
+ bindir: ${prefix}/bin
+ sbindir: ${prefix}/sbin
+ libdir: ${prefix}/lib
+ libexecdir: ${prefix}/lib/apr
+ mandir: ${prefix}/share/man
+ sysconfdir: /etc/httpd
+ datadir: /usr/local/httpd
+ installbuilddir: ${datadir}/build
+ includedir: ${prefix}/include/apr
+ localstatedir: /var/lib/httpd
+ runtimedir: /var/run
+</Layout>
+
+# BSD/OS layout
+<Layout BSDI>
+ prefix: /var/www
+ exec_prefix: /usr/contrib
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec/apr
+ mandir: ${exec_prefix}/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${datadir}/build
+ includedir: ${exec_prefix}/include/apr
+ localstatedir: /var
+ runtimedir: ${localstatedir}/run
+</Layout>
+
+# Solaris 8 Layout
+<Layout Solaris>
+ prefix: /usr/apr
+ exec_prefix: ${prefix}
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/bin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/libexec
+ mandir: ${exec_prefix}/man
+ sysconfdir: /etc/apr
+ datadir: /var/apr
+ installbuilddir: ${datadir}/build
+ includedir: ${exec_prefix}/include
+ localstatedir: ${prefix}
+ runtimedir: /var/run
+</Layout>
+
+# OpenBSD Layout
+<Layout OpenBSD>
+ prefix: /var/www
+ exec_prefix: /usr
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/lib/apr/modules
+ mandir: ${exec_prefix}/share/man
+ sysconfdir: ${prefix}/conf
+ datadir: ${prefix}
+ installbuilddir: ${prefix}/build
+ includedir: ${exec_prefix}/lib/apr/include
+ localstatedir: ${prefix}
+ runtimedir: ${prefix}/logs
+</Layout>
+
+# Debian layout
+<Layout Debian>
+ prefix:
+ exec_prefix: ${prefix}/usr
+ bindir: ${exec_prefix}/bin
+ sbindir: ${exec_prefix}/sbin
+ libdir: ${exec_prefix}/lib
+ libexecdir: ${exec_prefix}/lib/apr/modules
+ mandir: ${exec_prefix}/share/man
+ datadir: ${exec_prefix}/share/apr
+ includedir: ${exec_prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+ localstatedir: ${prefix}/var/run
+ runtimedir: ${prefix}/var/run
+ infodir: ${exec_prefix}/share/info
+ libsuffix -${TCNATIVE_MAJOR_VERSION}
+ installbuilddir: ${prefix}/usr/share/apache2/build
+</Layout>
--- /dev/null
+dnl
+dnl Process this file with autoconf to produce a configure script
+dnl
+
+AC_PREREQ(2.13)
+AC_INIT(configure.in)
+
+AC_CONFIG_AUX_DIR(build)
+
+sinclude(build/apr_common.m4)
+sinclude(build/tcnative.m4)
+sinclude(build/find_apr.m4)
+
+dnl Generate ./config.nice for reproducing runs of configure
+dnl
+APR_CONFIG_NICE(config.nice)
+
+dnl # Some initial steps for configuration. We setup the default directory
+dnl # and which files are to be configured.
+
+dnl Absolute source/build directory
+abs_srcdir=`(cd $srcdir && pwd)`
+abs_builddir=`pwd`
+
+if test "$abs_builddir" != "$abs_srcdir"; then
+ USE_VPATH=1
+ TCN_CONFIG_LOCATION=build
+else
+ TCN_CONFIG_LOCATION=source
+fi
+
+AC_SUBST(TCN_CONFIG_LOCATION)
+AC_CANONICAL_SYSTEM
+AC_PROG_INSTALL
+
+dnl
+dnl compute the top directory of the build
+dnl note: this is needed for LIBTOOL and exporting the bundled Expat
+dnl
+top_builddir="$abs_builddir"
+AC_SUBST(top_builddir)
+AC_SUBST(abs_srcdir)
+AC_SUBST(abs_builddir)
+
+dnl Initialize mkdir -p functionality.
+APR_MKDIR_P_CHECK($abs_srcdir/build/mkdir.sh)
+
+dnl get our version information
+get_version="$abs_srcdir/build/get-version.sh"
+version_hdr="$abs_srcdir/include/tcn_version.h"
+TCNATIVE_MAJOR_VERSION="`$get_version major $version_hdr TCN`"
+TCNATIVE_DOTTED_VERSION="`$get_version all $version_hdr TCN`"
+TCNATIVE_LIBTOOL_VERSION="`$get_version libtool $version_hdr TCN`"
+
+AC_SUBST(TCNATIVE_DOTTED_VERSION)
+AC_SUBST(TCNATIVE_MAJOR_VERSION)
+AC_SUBST(TCNATIVE_LIBTOOL_VERSION)
+
+echo "Tomcat Native Version: ${TCNATIVE_DOTTED_VERSION}"
+
+dnl Enable the layout handling code, then reparse the prefix-style
+dnl arguments due to autoconf being a PITA.
+APR_ENABLE_LAYOUT(tcnative)
+APR_PARSE_ARGUMENTS
+
+dnl
+dnl set up the compilation flags and stuff
+dnl
+
+TCNATIVE_INCLUDES=""
+TCNATIVE_PRIV_INCLUDES="-I$top_builddir/include"
+
+dnl
+dnl Find the APR includes directory and (possibly) the source (base) dir.
+dnl
+TCN_FIND_APR
+
+dnl
+dnl even though we use apr_rules.mk for building apr-util, we need
+dnl to grab CC and CPP ahead of time so that apr-util config tests
+dnl use the same compiler as APR; we need the same compiler options
+dnl and feature test macros as well
+dnl
+APR_SETIFNULL(CC, `$apr_config --cc`)
+APR_SETIFNULL(CPP, `$apr_config --cpp`)
+
+AC_PROG_INSTALL
+
+dnl
+dnl Find the JVM related information
+dnl
+TCN_FIND_JDK
+TCN_SABLEVM
+
+dnl MAC OS X does not used include but Headers
+if test -d ${JAVA_HOME}/Headers; then
+ JAVA_INC=Headers
+else
+ JAVA_INC=include
+fi
+APR_ADDTO(TCNATIVE_PRIV_INCLUDES,[-I$JAVA_HOME/$JAVA_INC])
+
+dnl sableVM does not have/need $JAVA_OS/jni_md.h
+if test "$SABLEVM" = "NONE"
+then
+ TCN_FIND_JDK_OS
+ if test -z "${JAVA_OS}"; then
+ AC_MSG_RESULT([jni_md.h found in $JAVA_HOME/$JAVA_INC])
+ else
+ APR_ADDTO(TCNATIVE_PRIV_INCLUDES,[-I$JAVA_HOME/$JAVA_INC/$JAVA_OS])
+ fi
+fi
+
+AC_SUBST(JAVA_HOME)
+AC_SUBST(JAVA_PLATFORM)
+AC_SUBST(JAVA_OS)
+
+
+dnl
+dnl Detect openssl toolkit installation
+dnl
+TCN_CHECK_SSL_TOOLKIT
+
+so_ext=$APR_SO_EXT
+lib_target=$APR_LIB_TARGET
+AC_SUBST(so_ext)
+AC_SUBST(lib_target)
+
+TCNATIVE_LIBNAME="tcnative${libsuffix}"
+AC_SUBST(TCNATIVE_LIBNAME)
+
+EXTRA_OS_LINK=""
+host_alias=`uname -s`
+case "$host_alias" in
+ dnl ### BeOS requires that ALL symbols resolve at LINK time!
+ dnl ###
+ dnl ### So, if we're building on BeOS then we need to add in the
+ dnl ### apr and expat libraries to the build or it'll die a truly horrible
+ dnl ### death. We now use the apr-config tool to determine the correct
+ dnl ### library to link against :)
+*AIX*|*Darwin*|*BeOS*)
+ dnl need such stuff as -liconv to be specified when building libaprutil.la
+ EXTRA_OS_LINK='$(TCNATIVE_LDFLAGS) $(TCNATIVE_LIBS)'
+ ;;
+*)
+ ;;
+esac
+
+AC_SUBST(EXTRA_OS_LINK)
+
+dnl CFLAGS for maintainer mode
+dnl it also allows the CFLAGS environment variable.
+CFLAGS="${CFLAGS}"
+AC_ARG_ENABLE(
+maintainer-mode,
+[ --enable-maintainer-mode Turn on debugging and compile time warnings],
+[
+ if test "$GCC" = "yes"; then
+ CFLAGS="${CFLAGS} -DDEBUG -Wall"
+ else
+ CFLAGS="${CFLAGS} -DDEBUG"
+ fi
+AC_MSG_RESULT([...Enabling Maintainer mode...])
+])
+
+dnl
+dnl Prep all the flags and stuff for compilation and export to other builds
+dnl
+APR_ADDTO(TCNATIVE_LIBS, [$LIBS])
+APR_ADDTO(TCNATIVE_LIBS, [$APR_LIBS])
+APR_ADDTO(TCNATIVE_LDFLAGS, [$LDFLAGS])
+
+# Link libkstat for Solaris
+case $host in
+ *-solaris2*)
+ APR_ADDTO(TCNATIVE_LIBS, -lkstat)
+ ;;
+ *)
+ ;;
+esac
+
+AC_SUBST(TCNATIVE_EXPORT_LIBS)
+AC_SUBST(TCNATIVE_PRIV_INCLUDES)
+AC_SUBST(TCNATIVE_INCLUDES)
+AC_SUBST(TCNATIVE_LDFLAGS)
+AC_SUBST(TCNATIVE_LIBS)
+AC_SUBST(CFLAGS)
+AC_SUBST(CPPFLAGS)
+
+dnl copy apr's rules.mk into our build directory.
+if test ! -d ./build; then
+ $mkdir_p build
+fi
+cp $APR_BUILD_DIR/apr_rules.mk $abs_builddir/build/rules.mk
+
+
+dnl
+dnl BSD/OS (BSDi) needs to use a different include syntax in the Makefiles
+dnl
+case "$host_alias" in
+*bsdi* | BSD/OS)
+ # Check whether they've installed GNU make
+ if make --version > /dev/null 2>&1; then
+ INCLUDE_RULES="include $abs_builddir/build/rules.mk"
+ INCLUDE_OUTPUTS="include $abs_srcdir/build-outputs.mk"
+ else
+ INCLUDE_RULES=".include \"$abs_builddir/build/rules.mk\""
+ INCLUDE_OUTPUTS=".include \"$abs_srcdir/build-outputs.mk\""
+ fi
+ ;;
+*)
+ INCLUDE_RULES="include $abs_builddir/build/rules.mk"
+ INCLUDE_OUTPUTS="include $abs_srcdir/build-outputs.mk"
+ ;;
+esac
+
+AC_SUBST(INCLUDE_RULES)
+AC_SUBST(INCLUDE_OUTPUTS)
+
+if test -d $srcdir/test; then
+ test_Makefile="test/Makefile"
+fi
+
+dnl
+dnl everthing is done.
+MAKEFILES="Makefile"
+AC_OUTPUT([
+ tcnative.pc
+ $MAKEFILES
+ ],[
+TCNATIVE_MAJOR_VERSION=$TCNATIVE_MAJOR_VERSION
+])
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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$
+ */
+
+#ifndef SSL_PRIVATE_H
+#define SSL_PRIVATE_H
+
+/* Exclude unused OpenSSL features
+ * even if the OpenSSL supports them
+ */
+#ifndef OPENSSL_NO_IDEA
+#define OPENSSL_NO_IDEA
+#endif
+#ifndef OPENSSL_NO_KRB5
+#define OPENSSL_NO_KRB5
+#endif
+#ifndef OPENSSL_NO_MDC2
+#define OPENSSL_NO_MDC2
+#endif
+#ifndef OPENSSL_NO_RC5
+#define OPENSSL_NO_RC5
+#endif
+
+/* OpenSSL headers */
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#include <openssl/md5.h>
+/* Avoid tripping over an engine build installed globally and detected
+ * when the user points at an explicit non-engine flavor of OpenSSL
+ */
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
+
+#ifndef RAND_MAX
+#include <limits.h>
+#define RAND_MAX INT_MAX
+#endif
+
+#define SSL_ALGO_UNKNOWN (0)
+#define SSL_ALGO_RSA (1<<0)
+#define SSL_ALGO_DSA (1<<1)
+#define SSL_ALGO_ALL (SSL_ALGO_RSA|SSL_ALGO_DSA)
+
+#define SSL_AIDX_RSA (0)
+#define SSL_AIDX_DSA (1)
+#define SSL_AIDX_MAX (2)
+
+/*
+ * Define IDs for the temporary RSA keys and DH params
+ */
+
+#define SSL_TMP_KEY_RSA_512 (0)
+#define SSL_TMP_KEY_RSA_1024 (1)
+#define SSL_TMP_KEY_RSA_2048 (2)
+#define SSL_TMP_KEY_RSA_4096 (3)
+#define SSL_TMP_KEY_DH_512 (4)
+#define SSL_TMP_KEY_DH_1024 (5)
+#define SSL_TMP_KEY_DH_2048 (6)
+#define SSL_TMP_KEY_DH_4096 (7)
+#define SSL_TMP_KEY_MAX (8)
+
+#define SSL_CRT_FORMAT_UNDEF (0)
+#define SSL_CRT_FORMAT_ASN1 (1)
+#define SSL_CRT_FORMAT_TEXT (2)
+#define SSL_CRT_FORMAT_PEM (3)
+#define SSL_CRT_FORMAT_NETSCAPE (4)
+#define SSL_CRT_FORMAT_PKCS12 (5)
+#define SSL_CRT_FORMAT_SMIME (6)
+#define SSL_CRT_FORMAT_ENGINE (7)
+/* XXX this stupid macro helps us to avoid
+ * adding yet another param to load_*key()
+ */
+#define SSL_KEY_FORMAT_IISSGC (8)
+
+/*
+ * Define the SSL options
+ */
+#define SSL_OPT_NONE (0)
+#define SSL_OPT_RELSET (1<<0)
+#define SSL_OPT_STDENVVARS (1<<1)
+#define SSL_OPT_EXPORTCERTDATA (1<<3)
+#define SSL_OPT_FAKEBASICAUTH (1<<4)
+#define SSL_OPT_STRICTREQUIRE (1<<5)
+#define SSL_OPT_OPTRENEGOTIATE (1<<6)
+#define SSL_OPT_ALL (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE)
+
+/*
+ * Define the SSL Protocol options
+ */
+#define SSL_PROTOCOL_NONE (0)
+#define SSL_PROTOCOL_SSLV2 (1<<0)
+#define SSL_PROTOCOL_SSLV3 (1<<1)
+#define SSL_PROTOCOL_TLSV1 (1<<2)
+#define SSL_PROTOCOL_ALL (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1)
+
+#define SSL_MODE_CLIENT (0)
+#define SSL_MODE_SERVER (1)
+#define SSL_MODE_COMBINED (2)
+
+#define SSL_BIO_FLAG_RDONLY (1<<0)
+#define SSL_BIO_FLAG_CALLBACK (1<<1)
+#define SSL_DEFAULT_CACHE_SIZE (256)
+#define SSL_DEFAULT_VHOST_NAME ("_default_:443")
+#define SSL_MAX_STR_LEN (2048)
+#define SSL_MAX_PASSWORD_LEN (256)
+
+#define SSL_CVERIFY_UNSET (-1)
+#define SSL_CVERIFY_NONE (0)
+#define SSL_CVERIFY_OPTIONAL (1)
+#define SSL_CVERIFY_REQUIRE (2)
+#define SSL_CVERIFY_OPTIONAL_NO_CA (3)
+#define SSL_VERIFY_PEER_STRICT (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+
+#define SSL_SHUTDOWN_TYPE_UNSET (0)
+#define SSL_SHUTDOWN_TYPE_STANDARD (1)
+#define SSL_SHUTDOWN_TYPE_UNCLEAN (2)
+#define SSL_SHUTDOWN_TYPE_ACCURATE (3)
+
+#define SSL_TO_APR_ERROR(X) (APR_OS_START_USERERR + 1000 + X)
+
+#define SSL_INFO_SESSION_ID (0x0001)
+#define SSL_INFO_CIPHER (0x0002)
+#define SSL_INFO_CIPHER_USEKEYSIZE (0x0003)
+#define SSL_INFO_CIPHER_ALGKEYSIZE (0x0004)
+#define SSL_INFO_CIPHER_VERSION (0x0005)
+#define SSL_INFO_CIPHER_DESCRIPTION (0x0006)
+#define SSL_INFO_PROTOCOL (0x0007)
+
+#define SSL_INFO_CLIENT_S_DN (0x0010)
+#define SSL_INFO_CLIENT_I_DN (0x0020)
+#define SSL_INFO_SERVER_S_DN (0x0040)
+#define SSL_INFO_SERVER_I_DN (0x0080)
+
+#define SSL_INFO_DN_COUNTRYNAME (0x0001)
+#define SSL_INFO_DN_STATEORPROVINCENAME (0x0002)
+#define SSL_INFO_DN_LOCALITYNAME (0x0003)
+#define SSL_INFO_DN_ORGANIZATIONNAME (0x0004)
+#define SSL_INFO_DN_ORGANIZATIONALUNITNAME (0x0005)
+#define SSL_INFO_DN_COMMONNAME (0x0006)
+#define SSL_INFO_DN_TITLE (0x0007)
+#define SSL_INFO_DN_INITIALS (0x0008)
+#define SSL_INFO_DN_GIVENNAME (0x0009)
+#define SSL_INFO_DN_SURNAME (0x000A)
+#define SSL_INFO_DN_DESCRIPTION (0x000B)
+#define SSL_INFO_DN_UNIQUEIDENTIFIER (0x000C)
+#define SSL_INFO_DN_EMAILADDRESS (0x000D)
+
+#define SSL_INFO_CLIENT_MASK (0x0100)
+
+#define SSL_INFO_CLIENT_M_VERSION (0x0101)
+#define SSL_INFO_CLIENT_M_SERIAL (0x0102)
+#define SSL_INFO_CLIENT_V_START (0x0103)
+#define SSL_INFO_CLIENT_V_END (0x0104)
+#define SSL_INFO_CLIENT_A_SIG (0x0105)
+#define SSL_INFO_CLIENT_A_KEY (0x0106)
+#define SSL_INFO_CLIENT_CERT (0x0107)
+#define SSL_INFO_CLIENT_V_REMAIN (0x0108)
+
+#define SSL_INFO_SERVER_MASK (0x0200)
+
+#define SSL_INFO_SERVER_M_VERSION (0x0201)
+#define SSL_INFO_SERVER_M_SERIAL (0x0202)
+#define SSL_INFO_SERVER_V_START (0x0203)
+#define SSL_INFO_SERVER_V_END (0x0204)
+#define SSL_INFO_SERVER_A_SIG (0x0205)
+#define SSL_INFO_SERVER_A_KEY (0x0206)
+#define SSL_INFO_SERVER_CERT (0x0207)
+#define SSL_INFO_CLIENT_CERT_CHAIN (0x0400)
+
+#define SSL_VERIFY_ERROR_IS_OPTIONAL(errnum) \
+ ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) \
+ || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \
+ || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) \
+ || (errnum == X509_V_ERR_CERT_UNTRUSTED) \
+ || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
+
+
+
+#define SSL_DEFAULT_PASS_PROMPT "Some of your private key files are encrypted for security reasons.\n" \
+ "In order to read them you have to provide the pass phrases.\n" \
+ "Enter password :"
+
+extern void *SSL_temp_keys[SSL_TMP_KEY_MAX];
+
+typedef struct {
+ /* client can have any number of cert/key pairs */
+ const char *cert_file;
+ const char *cert_path;
+ STACK_OF(X509_INFO) *certs;
+} ssl_pkc_t;
+
+typedef struct tcn_ssl_ctxt_t tcn_ssl_ctxt_t;
+
+typedef struct {
+ char password[SSL_MAX_PASSWORD_LEN];
+ const char *prompt;
+ tcn_callback_t cb;
+} tcn_pass_cb_t;
+
+extern tcn_pass_cb_t tcn_password_callback;
+
+struct tcn_ssl_ctxt_t {
+ apr_pool_t *pool;
+ SSL_CTX *ctx;
+ BIO *bio_os;
+ BIO *bio_is;
+
+ unsigned char context_id[MD5_DIGEST_LENGTH];
+
+ int protocol;
+ /* we are one or the other */
+ int mode;
+
+ /* certificate revocation list */
+ X509_STORE *crl;
+ /* pointer to the context verify store */
+ X509_STORE *store;
+ const char *cert_files[SSL_AIDX_MAX];
+ const char *key_files[SSL_AIDX_MAX];
+ X509 *certs[SSL_AIDX_MAX];
+ EVP_PKEY *keys[SSL_AIDX_MAX];
+
+ int ca_certs;
+ int shutdown_type;
+ char *rand_file;
+
+ const char *cipher_suite;
+ /* for client or downstream server authentication */
+ int verify_depth;
+ int verify_mode;
+ tcn_pass_cb_t *cb_data;
+};
+
+typedef struct {
+ apr_pool_t *pool;
+ tcn_ssl_ctxt_t *ctx;
+ SSL *ssl;
+ X509 *peer;
+ int shutdown_type;
+ apr_socket_t *sock;
+ apr_pollset_t *pollset;
+} tcn_ssl_conn_t;
+
+
+#define SSL_CTX_get_extra_certs(ctx) ((ctx)->extra_certs)
+#define SSL_CTX_set_extra_certs(ctx, value) \
+ TCN_BEGIN_MACRO \
+ (ctx)->extra_certs = (value); \
+ TCN_END_MACRO
+
+/*
+ * Additional Functions
+ */
+void SSL_init_app_data2_idx(void);
+void *SSL_get_app_data2(SSL *);
+void SSL_set_app_data2(SSL *, void *);
+int SSL_password_prompt(tcn_pass_cb_t *);
+int SSL_password_callback(char *, int, int, void *);
+void SSL_BIO_close(BIO *);
+void SSL_BIO_doref(BIO *);
+DH *SSL_dh_get_tmp_param(int);
+DH *SSL_dh_get_param_from_file(const char *);
+RSA *SSL_callback_tmp_RSA(SSL *, int, int);
+DH *SSL_callback_tmp_DH(SSL *, int, int);
+void SSL_vhost_algo_id(const unsigned char *, unsigned char *, int);
+int SSL_CTX_use_certificate_chain(SSL_CTX *, const char *, int);
+int SSL_callback_SSL_verify(int, X509_STORE_CTX *);
+int SSL_rand_seed(const char *file);
+#endif /* SSL_PRIVATE_H */
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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$
+ */
+
+#ifndef TCN_H
+#define TCN_H
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_portable.h"
+#include "apr_network_io.h"
+#include "apr_strings.h"
+
+#ifndef APR_HAS_THREADS
+#error "Missing APR_HAS_THREADS support from APR."
+#endif
+
+#if defined(DEBUG) || defined(_DEBUG)
+/* On -DDEBUG use the statistics */
+#ifndef TCN_DO_STATISTICS
+#define TCN_DO_STATISTICS
+#endif
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <process.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "tcn_api.h"
+
+
+#if defined(_DEBUG) || defined(DEBUG)
+#include <assert.h>
+#define TCN_ASSERT(x) assert((x))
+#else
+#define TCN_ASSERT(x) (void)0
+#endif
+
+#ifndef APR_MAX_IOVEC_SIZE
+#define APR_MAX_IOVEC_SIZE 1024
+#endif
+
+#define TCN_TIMEUP APR_OS_START_USERERR + 1
+#define TCN_EAGAIN APR_OS_START_USERERR + 2
+#define TCN_EINTR APR_OS_START_USERERR + 3
+#define TCN_EINPROGRESS APR_OS_START_USERERR + 4
+#define TCN_ETIMEDOUT APR_OS_START_USERERR + 5
+
+#define TCN_LOG_EMERG 1
+#define TCN_LOG_ERROR 2
+#define TCN_LOG_NOTICE 3
+#define TCN_LOG_WARN 4
+#define TCN_LOG_INFO 5
+#define TCN_LOG_DEBUG 6
+
+#define TCN_ERROR_WRAP(E) \
+ if (APR_STATUS_IS_TIMEUP(E)) \
+ (E) = TCN_TIMEUP; \
+ else if (APR_STATUS_IS_EAGAIN(E)) \
+ (E) = TCN_EAGAIN; \
+ else if (APR_STATUS_IS_EINTR(E)) \
+ (E) = TCN_EINTR; \
+ else if (APR_STATUS_IS_EINPROGRESS(E)) \
+ (E) = TCN_EINPROGRESS; \
+ else if (APR_STATUS_IS_ETIMEDOUT(E)) \
+ (E) = TCN_ETIMEDOUT; \
+ else \
+ (E) = (E)
+
+#define TCN_CLASS_PATH "org/apache/tomcat/jni/"
+#define TCN_FINFO_CLASS TCN_CLASS_PATH "FileInfo"
+#define TCN_AINFO_CLASS TCN_CLASS_PATH "Sockaddr"
+#define TCN_ERROR_CLASS TCN_CLASS_PATH "Error"
+#define TCN_PARENT_IDE "TCN_PARENT_ID"
+
+#define UNREFERENCED(P) (P) = (P)
+#define UNREFERENCED_STDARGS e = e; o = o
+#ifdef WIN32
+#define LLT(X) (X)
+#else
+#define LLT(X) ((long)(X))
+#endif
+#define P2J(P) ((jlong)LLT(P))
+#define J2P(P, T) ((T)LLT((jlong)P))
+/* On stack buffer size */
+#define TCN_BUFFER_SZ 8192
+#define TCN_STDARGS JNIEnv *e, jobject o
+#define TCN_IMPARGS JNIEnv *e, jobject o, void *sock
+#define TCN_IMPCALL(X) e, o, X->opaque
+
+#define TCN_IMPLEMENT_CALL(RT, CL, FN) \
+ JNIEXPORT RT JNICALL Java_org_apache_tomcat_jni_##CL##_##FN
+
+#define TCN_IMPLEMENT_METHOD(RT, FN) \
+ static RT method_##FN
+
+#define TCN_GETNET_METHOD(FN) method_##FN
+
+#define TCN_SOCKET_UNKNOWN 0
+#define TCN_SOCKET_APR 1
+#define TCN_SOCKET_SSL 2
+#define TCN_SOCKET_UNIX 3
+#define TCN_SOCKET_NTPIPE 4
+
+#define TCN_SOCKET_GET_POOL 0
+#define TCN_SOCKET_GET_IMPL 1
+#define TCN_SOCKET_GET_APRS 2
+#define TCN_SOCKET_GET_TYPE 3
+
+typedef struct {
+ int type;
+ apr_status_t (*cleanup)(void *);
+ apr_status_t (APR_THREAD_FUNC *close) (apr_socket_t *);
+ apr_status_t (APR_THREAD_FUNC *shutdown) (apr_socket_t *, apr_shutdown_how_e);
+ apr_status_t (APR_THREAD_FUNC *opt_get)(apr_socket_t *, apr_int32_t, apr_int32_t *);
+ apr_status_t (APR_THREAD_FUNC *opt_set)(apr_socket_t *, apr_int32_t, apr_int32_t);
+ apr_status_t (APR_THREAD_FUNC *timeout_get)(apr_socket_t *, apr_interval_time_t *);
+ apr_status_t (APR_THREAD_FUNC *timeout_set)(apr_socket_t *, apr_interval_time_t);
+ apr_status_t (APR_THREAD_FUNC *send) (apr_socket_t *, const char *, apr_size_t *);
+ apr_status_t (APR_THREAD_FUNC *sendv)(apr_socket_t *, const struct iovec *, apr_int32_t, apr_size_t *);
+ apr_status_t (APR_THREAD_FUNC *recv) (apr_socket_t *, char *, apr_size_t *);
+} tcn_nlayer_t;
+
+typedef struct {
+ apr_pool_t *pool;
+ apr_socket_t *sock;
+ void *opaque;
+ char *jsbbuff;
+ char *jrbbuff;
+ tcn_nlayer_t *net;
+} tcn_socket_t;
+
+/* Private helper functions */
+void tcn_Throw(JNIEnv *, const char *, ...);
+void tcn_ThrowException(JNIEnv *, const char *);
+void tcn_ThrowMemoryException(JNIEnv *, const char *, int, const char *);
+void tcn_ThrowAPRException(JNIEnv *, apr_status_t);
+jstring tcn_new_string(JNIEnv *, const char *);
+jstring tcn_new_stringn(JNIEnv *, const char *, size_t);
+jbyteArray tcn_new_arrayb(JNIEnv *, const unsigned char *, size_t);
+jobjectArray tcn_new_arrays(JNIEnv *env, size_t len);
+char *tcn_get_string(JNIEnv *, jstring);
+char *tcn_strdup(JNIEnv *, jstring);
+char *tcn_pstrdup(JNIEnv *, jstring, apr_pool_t *);
+apr_status_t tcn_load_finfo_class(JNIEnv *, jclass);
+apr_status_t tcn_load_ainfo_class(JNIEnv *, jclass);
+
+#define J2S(V) c##V
+#define J2L(V) p##V
+
+#define J2T(T) (apr_time_t)((T))
+
+#define TCN_BEGIN_MACRO if (1) {
+#define TCN_END_MACRO } else (void)(0)
+
+#define TCN_ALLOC_CSTRING(V) \
+ const char *c##V = V ? (const char *)((*e)->GetStringUTFChars(e, V, 0)) : NULL
+
+#define TCN_FREE_CSTRING(V) \
+ if (c##V) (*e)->ReleaseStringUTFChars(e, V, c##V)
+
+#define TCN_ALLOC_JSTRING(V) \
+ char *c##V = tcn_get_string(e, (V))
+
+#define AJP_TO_JSTRING(V) (*e)->NewStringUTF((e), (V))
+
+#define TCN_FREE_JSTRING(V) \
+ TCN_BEGIN_MACRO \
+ if (c##V) \
+ free(c##V); \
+ TCN_END_MACRO
+
+#define TCN_CHECK_ALLOCATED(x) \
+ if (x == NULL) { \
+ tcn_ThrowMemoryException(e, __FILE__, __LINE__, \
+ "APR memory allocation failed"); \
+ goto cleanup; \
+ } else (void)(0)
+
+#define TCN_THROW_IF_ERR(x, r) \
+ TCN_BEGIN_MACRO \
+ apr_status_t R = (x); \
+ if (R != APR_SUCCESS) { \
+ tcn_ThrowAPRException(e, R); \
+ (r) = 0; \
+ goto cleanup; \
+ } \
+ TCN_END_MACRO
+
+#define TCN_THROW_OS_ERROR(E) \
+ tcn_ThrowAPRException((E), apr_get_os_error())
+
+#define TCN_LOAD_CLASS(E, C, N, R) \
+ TCN_BEGIN_MACRO \
+ jclass _##C = (*(E))->FindClass((E), N); \
+ if (_##C == NULL) { \
+ (*(E))->ExceptionClear((E)); \
+ return R; \
+ } \
+ C = (*(E))->NewGlobalRef((E), _##C); \
+ (*(E))->DeleteLocalRef((E), _##C); \
+ TCN_END_MACRO
+
+#define TCN_UNLOAD_CLASS(E, C) \
+ (*(E))->DeleteGlobalRef((E), (C))
+
+#define TCN_IS_NULL(E, O) \
+ ((*(E))->IsSameObject((E), (O), NULL) == JNI_TRUE)
+
+#define TCN_GET_METHOD(E, C, M, N, S, R) \
+ TCN_BEGIN_MACRO \
+ M = (*(E))->GetMethodID((E), C, N, S); \
+ if (M == NULL) { \
+ return R; \
+ } \
+ TCN_END_MACRO
+
+#define TCN_MAX_METHODS 8
+
+typedef struct {
+ jobject obj;
+ jmethodID mid[TCN_MAX_METHODS];
+ void *opaque;
+} tcn_callback_t;
+
+#define TCN_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define TCN_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#ifdef WIN32
+#define TCN_ALLOC_WSTRING(V) \
+ jsize wl##V = (*e)->GetStringLength(e, V); \
+ const jchar *ws##V = V ? (const jchar *)((*e)->GetStringChars(e, V, 0)) : NULL; \
+ jchar *w##V = NULL
+
+#define TCN_INIT_WSTRING(V) \
+ w##V = (jchar *)malloc((wl##V + 1) * sizeof(jchar)); \
+ wcsncpy(w##V, ws##V, wl##V); \
+ w##V[wl##V] = 0
+
+#define TCN_FREE_WSTRING(V) \
+ if (ws##V) (*e)->ReleaseStringChars(e, V, ws##V); \
+ if (ws##V) free (w##V)
+
+#define J2W(V) w##V
+
+#endif
+
+#if !APR_HAVE_IPV6
+#define APR_INET6 APR_INET
+#endif
+
+#define GET_S_FAMILY(T, F) \
+ if (F == 0) T = APR_UNSPEC; \
+ else if (F == 1) T = APR_INET; \
+ else if (F == 2) T = APR_INET6; \
+ else T = F
+
+#define GET_S_TYPE(T, F) \
+ if (F == 0) T = SOCK_STREAM; \
+ else if (F == 1) T = SOCK_DGRAM; \
+ else T = F
+
+#endif /* TCN_H */
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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$
+ */
+
+#ifndef TCN_API_H
+#define TCN_API_H
+
+#include "apr.h"
+#include "apr_general.h"
+#include "apr_pools.h"
+#include "apr_portable.h"
+#include "apr_network_io.h"
+#include "apr_strings.h"
+
+#ifndef APR_HAS_THREADS
+#error "Missing APR_HAS_THREADS support from APR."
+#endif
+#include <jni.h>
+
+/**
+ * TCN_DECLARE_EXPORT is defined when building the TCN dynamic library,
+ * so that all public symbols are exported.
+ *
+ * TCN_DECLARE_STATIC is defined when including the TCN public headers,
+ * to provide static linkage when the dynamic library may be unavailable.
+ *
+ * TCN_DECLARE_STATIC and TCN_DECLARE_EXPORT are left undefined when
+ * including the TCN public headers, to import and link the symbols from
+ * the dynamic TCN library and assure appropriate indirection and calling
+ * conventions at compile time.
+ */
+
+#if !defined(WIN32)
+/**
+ * The public TCN functions are declared with TCN_DECLARE(), so they may
+ * use the most appropriate calling convention. Public APR functions with
+ * variable arguments must use TCN_DECLARE_NONSTD().
+ *
+ * @deffunc TCN_DECLARE(rettype) apr_func(args);
+ */
+#define TCN_DECLARE(type) type
+/**
+ * The public TCN functions using variable arguments are declared with
+ * TCN_DECLARE_NONSTD(), as they must use the C language calling convention.
+ *
+ * @deffunc TCN_DECLARE_NONSTD(rettype) apr_func(args, ...);
+ */
+#define TCN_DECLARE_NONSTD(type) type
+/**
+ * The public TCN variables are declared with TCN_DECLARE_DATA.
+ * This assures the appropriate indirection is invoked at compile time.
+ *
+ * @deffunc TCN_DECLARE_DATA type apr_variable;
+ * @tip extern TCN_DECLARE_DATA type apr_variable; syntax is required for
+ * declarations within headers to properly import the variable.
+ */
+#define TCN_DECLARE_DATA
+#elif defined(TCN_DECLARE_STATIC)
+#define TCN_DECLARE(type) type __stdcall
+#define TCN_DECLARE_NONSTD(type) type
+#define TCN_DECLARE_DATA
+#elif defined(TCN_DECLARE_EXPORT)
+#define TCN_DECLARE(type) __declspec(dllexport) type __stdcall
+#define TCN_DECLARE_NONSTD(type) __declspec(dllexport) type
+#define TCN_DECLARE_DATA __declspec(dllexport)
+#else
+/**
+ * The public TCN functions are declared with TCN_DECLARE(), so they may
+ * use the most appropriate calling convention. Public APR functions with
+ * variable arguments must use TCN_DECLARE_NONSTD().
+ *
+ */
+#define TCN_DECLARE(type) __declspec(dllimport) type __stdcall
+/**
+ * The public TCN functions using variable arguments are declared with
+ * TCN_DECLARE_NONSTD(), as they must use the C language calling convention.
+ *
+ */
+#define TCN_DECLARE_NONSTD(type) __declspec(dllimport) type
+/**
+ * The public TCN variables are declared with TCN_DECLARE_DATA.
+ * This assures the appropriate indirection is invoked at compile time.
+ *
+ * @remark extern TCN_DECLARE_DATA type apr_variable; syntax is required for
+ * declarations within headers to properly import the variable.
+ */
+#define TCN_DECLARE_DATA __declspec(dllimport)
+#endif
+
+#if !defined(WIN32) || defined(TCN_MODULE_DECLARE_STATIC)
+/**
+ * Declare a dso module's exported module structure as TCN_MODULE_DECLARE_DATA.
+ *
+ * Unless TCN_MODULE_DECLARE_STATIC is defined at compile time, symbols
+ * declared with TCN_MODULE_DECLARE_DATA are always exported.
+ * @code
+ * module TCN_MODULE_DECLARE_DATA mod_tag
+ * @endcode
+ */
+#if defined(WIN32)
+#define TCN_MODULE_DECLARE(type) type __stdcall
+#else
+#define TCN_MODULE_DECLARE(type) type
+#endif
+#define TCN_MODULE_DECLARE_NONSTD(type) type
+#define TCN_MODULE_DECLARE_DATA
+#else
+/**
+ * TCN_MODULE_DECLARE_EXPORT is a no-op. Unless contradicted by the
+ * TCN_MODULE_DECLARE_STATIC compile-time symbol, it is assumed and defined.
+ */
+#define TCN_MODULE_DECLARE_EXPORT
+#define TCN_MODULE_DECLARE(type) __declspec(dllexport) type __stdcall
+#define TCN_MODULE_DECLARE_NONSTD(type) __declspec(dllexport) type
+#define TCN_MODULE_DECLARE_DATA __declspec(dllexport)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file tcn_api.h
+ * @brief
+ *
+ * Tomcat Native Public API
+ */
+
+/* Return global apr pool
+ */
+TCN_DECLARE(apr_pool_t *) tcn_get_global_pool(void);
+
+/* Return global String class
+ */
+TCN_DECLARE(jclass) tcn_get_string_class(void);
+
+/* Return global JVM initalized on JNI_OnLoad
+ */
+TCN_DECLARE(JavaVM *) tcn_get_java_vm(void);
+
+/* Get current thread JNIEnv
+ */
+TCN_DECLARE(jint) tcn_get_java_env(JNIEnv **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TCN_API_H */
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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$
+ */
+
+#ifndef TCN_VERSION_H
+#define TCN_VERSION_H
+
+#include "apr_version.h"
+
+#include "tcn.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file tcn_version.h
+ * @brief
+ *
+ * Tomcat Native Version
+ *
+ * There are several different mechanisms for accessing the version. There
+ * is a string form, and a set of numbers; in addition, there are constants
+ * which can be compiled into your application, and you can query the library
+ * being used for its actual version.
+ *
+ * Note that it is possible for an application to detect that it has been
+ * compiled against a different version of APU by use of the compile-time
+ * constants and the use of the run-time query function.
+ *
+ * TCN version numbering follows the guidelines specified in:
+ *
+ * http://apr.apache.org/versioning.html
+ */
+
+/* The numeric compile-time version constants. These constants are the
+ * authoritative version numbers for TCN.
+ */
+
+/** major version
+ * Major API changes that could cause compatibility problems for older
+ * programs such as structure size changes. No binary compatibility is
+ * possible across a change in the major version.
+ */
+#define TCN_MAJOR_VERSION 1
+
+/**
+ * Minor API changes that do not cause binary compatibility problems.
+ * Should be reset to 0 when upgrading TCN_MAJOR_VERSION
+ */
+#define TCN_MINOR_VERSION 1
+
+/** patch level */
+#define TCN_PATCH_VERSION 6
+
+/**
+ * This symbol is defined for internal, "development" copies of TCN. This
+ * symbol will be #undef'd for releases.
+ */
+#undef TCN_IS_DEV_VERSION
+
+
+/** The formatted string of APU's version */
+#define TCN_VERSION_STRING \
+ APR_STRINGIFY(TCN_MAJOR_VERSION) "."\
+ APR_STRINGIFY(TCN_MINOR_VERSION) "."\
+ APR_STRINGIFY(TCN_PATCH_VERSION)\
+ TCN_IS_DEV_STRING
+
+/** Internal: string form of the "is dev" flag */
+#ifdef TCN_IS_DEV_VERSION
+#define TCN_IS_DEV_STRING "-dev"
+#else
+#define TCN_IS_DEV_STRING ""
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TCN_VERSION_H */
--- /dev/null
+# Microsoft Developer Studio Project File - Name="libtcnative" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=libtcnative - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "libtcnative.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "libtcnative.mak" CFG="libtcnative - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "libtcnative - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "libtcnative - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "libtcnative - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "Release"
+# PROP Intermediate_Dir "Release"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Zi /O2 /Oy- /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "NDEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"Release\libtcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /opt:ref
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /out:"Release/libtcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll" /opt:ref
+
+!ELSEIF "$(CFG)" == "libtcnative - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "Debug"
+# PROP Intermediate_Dir "Debug"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W4 /GX /Zi /Od /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "_DEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"Debug\libtcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"Debug/libtcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll"
+
+!ENDIF
+
+# Begin Target
+
+# Name "libtcnative - Win32 Release"
+# Name "libtcnative - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\address.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\dir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\file.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\jnilib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\lock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\mmap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\multicast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\network.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\poll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\proc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\ssl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslcontext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslnetwork.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslutils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\stdlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\thread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\user.c
+# End Source File
+# End Group
+# Begin Group "Generated Files"
+
+# PROP Default_Filter ""
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\include\ssl_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_api.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_version.h
+# End Source File
+# End Group
+# Begin Group "Platform Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\os\win32\ntpipe.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\registry.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\system.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\os\win32\libtcnative.rc
+# End Source File
+# End Target
+# End Project
--- /dev/null
+Microsoft Developer Studio Workspace File, Format Version 6.00
+# WARNING: DO NOT EDIT OR DELETE THIS WORKSPACE FILE!
+
+###############################################################################
+
+Project: "apr"=..\apr\apr.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libapr"=..\apr\libapr.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+}}}
+
+###############################################################################
+
+Project: "libtcnative"=.\libtcnative.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name libapr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Project: "tcnative"=.\tcnative.dsp - Package Owner=<4>
+
+Package=<5>
+{{{
+}}}
+
+Package=<4>
+{{{
+ Begin Project Dependency
+ Project_Dep_Name apr
+ End Project Dependency
+}}}
+
+###############################################################################
+
+Global:
+
+Package=<5>
+{{{
+}}}
+
+Package=<3>
+{{{
+}}}
+
+###############################################################################
+
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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 "apr.h"
+#include "apr_pools.h"
+#include "apr_network_io.h"
+#include "apr_poll.h"
+
+#include "tcn.h"
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+ UNREFERENCED_STDARGS;
+ if (type == 2)
+ return JNI_TRUE;
+ else
+ return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+ jlongArray inf)
+{
+ UNREFERENCED_STDARGS;
+ UNREFERENCED(inf);
+ return APR_ENOTIMPL;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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 "apr.h"
+#include "apr_pools.h"
+#include "apr_network_io.h"
+#include "apr_poll.h"
+
+#include "tcn.h"
+#if defined(__linux__)
+#include <sys/sysinfo.h>
+#elif defined(sun)
+#include <unistd.h>
+#include <sys/swap.h>
+#include <procfs.h>
+#include <kstat.h>
+#include <sys/sysinfo.h>
+#endif
+
+#if defined(DARWIN)
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#endif
+
+#include <syslog.h>
+#include <stdarg.h>
+
+#ifndef LOG_WARN
+#define LOG_WARN LOG_WARNING
+#endif
+
+#if defined(sun)
+#define MAX_PROC_PATH_LEN 64
+#define MAX_CPUS 512
+#define PSINFO_T_SZ sizeof(psinfo_t)
+#define PRUSAGE_T_SZ sizeof(prusage_t)
+
+static int proc_open(const char *type)
+{
+ char proc_path[MAX_PROC_PATH_LEN+1];
+
+ sprintf(proc_path, "/proc/self/%s", type);
+ return open(proc_path, O_RDONLY);
+}
+
+static int proc_read(void *buf, const size_t size, int filedes)
+{
+ ssize_t bytes;
+
+ if (filedes >= 0) {
+ bytes = pread(filedes, buf, size, 0);
+ if (bytes != size)
+ return -1;
+ else
+ return 0;
+ }
+ else
+ return -1;
+}
+
+#endif
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+ UNREFERENCED_STDARGS;
+ if (type == 1)
+ return JNI_TRUE;
+#if defined(__linux__)
+ else if (type == 5)
+ return JNI_TRUE;
+#endif
+#if defined(sun)
+ else if (type == 6)
+ return JNI_TRUE;
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+ else if (type == 7)
+ return JNI_TRUE;
+#endif
+ else
+ return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+ jlongArray inf)
+{
+ jint rv;
+ int i;
+ jsize ilen = (*e)->GetArrayLength(e, inf);
+ jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
+
+ UNREFERENCED(o);
+ if (ilen < 16) {
+ return APR_EINVAL;
+ }
+ for (i = 0; i < 16; i++)
+ pvals[i] = 0;
+#if defined(__linux__)
+ {
+ struct sysinfo info;
+ if (sysinfo(&info))
+ rv = apr_get_os_error();
+ else {
+ pvals[0] = (jlong)(info.totalram * info.mem_unit);
+ pvals[1] = (jlong)(info.freeram * info.mem_unit);
+ pvals[2] = (jlong)(info.totalswap * info.mem_unit);
+ pvals[3] = (jlong)(info.freeswap * info.mem_unit);
+ pvals[4] = (jlong)(info.sharedram * info.mem_unit);
+ pvals[5] = (jlong)(info.bufferram * info.mem_unit);
+ pvals[6] = (jlong)(100 - (info.freeram * 100 / info.totalram));
+ rv = APR_SUCCESS;
+ }
+ }
+#elif defined(sun)
+ {
+ /* static variables with basic procfs info */
+ static long creation = 0; /* unix timestamp of process creation */
+ static int psinf_fd = 0; /* file descriptor for the psinfo procfs file */
+ static int prusg_fd = 0; /* file descriptor for the usage procfs file */
+ static size_t rss = 0; /* maximum of resident set size from previous calls */
+ /* static variables with basic kstat info */
+ static kstat_ctl_t *kstat_ctl = NULL; /* kstat control object, only initialized once */
+ static kstat_t *kstat_cpu[MAX_CPUS]; /* array of kstat objects for per cpu statistics */
+ static int cpu_count = 0; /* number of cpu structures found in kstat */
+ static kid_t kid = 0; /* kstat ID, for which the kstat_ctl holds the correct chain */
+ /* non-static variables - general use */
+ int res = 0; /* general result state */
+ /* non-static variables - sysinfo/swapctl use */
+ long ret_sysconf; /* value returned from sysconf call */
+ long tck_dividend; /* factor used by transforming tick numbers to milliseconds */
+ long tck_divisor; /* divisor used by transforming tick numbers to milliseconds */
+ long sys_pagesize = sysconf(_SC_PAGESIZE); /* size of a system memory page in bytes */
+ long sys_clk_tck = sysconf(_SC_CLK_TCK); /* number of system ticks per second */
+ struct anoninfo info; /* structure for information about sizes in anonymous memory system */
+ /* non-static variables - procfs use */
+ psinfo_t psinf; /* psinfo structure from procfs */
+ prusage_t prusg; /* usage structure from procfs */
+ size_t new_rss = 0; /* resident set size read from procfs */
+ time_t now; /* time needed for calculating process creation time */
+ /* non-static variables - kstat use */
+ kstat_t *kstat = NULL; /* kstat working pointer */
+ cpu_sysinfo_t cpu; /* cpu sysinfo working pointer */
+ kid_t new_kid = 0; /* kstat ID returned from chain update */
+ int new_kstat = 0; /* flag indicating, if kstat structure has changed since last call */
+
+ rv = APR_SUCCESS;
+
+ if (sys_pagesize <= 0) {
+ rv = apr_get_os_error();
+ }
+ else {
+ ret_sysconf = sysconf(_SC_PHYS_PAGES);
+ if (ret_sysconf >= 0) {
+ pvals[0] = (jlong)((jlong)sys_pagesize * ret_sysconf);
+ }
+ else {
+ rv = apr_get_os_error();
+ }
+ ret_sysconf = sysconf(_SC_AVPHYS_PAGES);
+ if (ret_sysconf >= 0) {
+ pvals[1] = (jlong)((jlong)sys_pagesize * ret_sysconf);
+ }
+ else {
+ rv = apr_get_os_error();
+ }
+ res=swapctl(SC_AINFO, &info);
+ if (res >= 0) {
+ pvals[2] = (jlong)((jlong)sys_pagesize * info.ani_max);
+ pvals[3] = (jlong)((jlong)sys_pagesize * info.ani_free);
+ pvals[6] = (jlong)(100 - (jlong)info.ani_free * 100 / info.ani_max);
+ }
+ else {
+ rv = apr_get_os_error();
+ }
+ }
+
+ if (psinf_fd == 0) {
+ psinf_fd = proc_open("psinfo");
+ }
+ res = proc_read(&psinf, PSINFO_T_SZ, psinf_fd);
+ if (res >= 0) {
+ new_rss = psinf.pr_rssize*1024;
+ pvals[13] = (jlong)(new_rss);
+ if (new_rss > rss) {
+ rss = new_rss;
+ }
+ pvals[14] = (jlong)(rss);
+ }
+ else {
+ psinf_fd = 0;
+ rv = apr_get_os_error();
+ }
+ if (prusg_fd == 0) {
+ prusg_fd = proc_open("usage");
+ }
+ res = proc_read(&prusg, PRUSAGE_T_SZ, prusg_fd);
+ if (res >= 0) {
+ if (creation <= 0) {
+ time(&now);
+ creation = (long)(now - (prusg.pr_tstamp.tv_sec -
+ prusg.pr_create.tv_sec));
+ }
+ pvals[10] = (jlong)(creation);
+ pvals[11] = (jlong)((jlong)prusg.pr_stime.tv_sec * 1000 +
+ (prusg.pr_stime.tv_nsec / 1000000));
+ pvals[12] = (jlong)((jlong)prusg.pr_utime.tv_sec * 1000 +
+ (prusg.pr_utime.tv_nsec / 1000000));
+ pvals[15] = (jlong)(prusg.pr_majf);
+ }
+ else {
+ prusg_fd = 0;
+ rv = apr_get_os_error();
+ }
+
+ if (sys_clk_tck <= 0) {
+ rv = apr_get_os_error();
+ }
+ else {
+ tck_dividend = 1000;
+ tck_divisor = sys_clk_tck;
+ for (i = 0; i < 3; i++) {
+ if (tck_divisor % 2 == 0) {
+ tck_divisor = tck_divisor / 2;
+ tck_dividend = tck_dividend / 2;
+ }
+ if (tck_divisor % 5 == 0) {
+ tck_divisor = tck_divisor / 5;
+ tck_dividend = tck_dividend / 5;
+ }
+ }
+ if (kstat_ctl == NULL) {
+ kstat_ctl = kstat_open();
+ kid = kstat_ctl->kc_chain_id;
+ new_kstat = 1;
+ } else {
+ new_kid = kstat_chain_update(kstat_ctl);
+ if (new_kid < 0) {
+ res=kstat_close(kstat_ctl);
+ kstat_ctl = kstat_open();
+ kid = kstat_ctl->kc_chain_id;
+ new_kstat = 1;
+ } else if (new_kid > 0 && kid != new_kid) {
+ kid = new_kid;
+ new_kstat = 1;
+ }
+ }
+ if (new_kstat) {
+ cpu_count = 0;
+ for (kstat = kstat_ctl->kc_chain; kstat; kstat = kstat->ks_next) {
+ if (strncmp(kstat->ks_name, "cpu_stat", 8) == 0) {
+ kstat_cpu[cpu_count++]=kstat;
+ }
+ }
+ }
+ for (i = 0; i < cpu_count; i++) {
+ new_kid = kstat_read(kstat_ctl, kstat_cpu[i], NULL);
+ if (new_kid >= 0) {
+ cpu = ((cpu_stat_t *)kstat_cpu[i]->ks_data)->cpu_sysinfo;
+ if ( tck_divisor == 1 ) {
+ pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend);
+ pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend);
+ pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend);
+ pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend);
+ } else {
+ pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend / tck_divisor);
+ pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend / tck_divisor);
+ pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend / tck_divisor);
+ pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend / tck_divisor);
+ }
+ }
+ }
+ }
+
+ /*
+ * The next two are not implemented yet for Solaris
+ * inf[4] - Amount of shared memory
+ * inf[5] - Memory used by buffers
+ *
+ */
+ }
+
+#elif defined(DARWIN)
+
+ uint64_t mem_total;
+ size_t len = sizeof(mem_total);
+
+ vm_statistics_data_t vm_info;
+ mach_msg_type_number_t info_count = HOST_VM_INFO_COUNT;
+
+ sysctlbyname("hw.memsize", &mem_total, &len, NULL, 0);
+ pvals[0] = (jlong)mem_total;
+
+ host_statistics(mach_host_self (), HOST_VM_INFO, (host_info_t)&vm_info, &info_count);
+ pvals[1] = (jlong)(((double)vm_info.free_count)*vm_page_size);
+ pvals[6] = (jlong)(100 - (pvals[1] * 100 / mem_total));
+ rv = APR_SUCCESS;
+
+/* DARWIN */
+#else
+ rv = APR_ENOTIMPL;
+#endif
+ (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+ return rv;
+}
+
+#define LOG_MSG_DOMAIN "Native"
+
+
+TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
+{
+ jstring str;
+ TCN_ALLOC_CSTRING(val);
+
+ UNREFERENCED(o);
+
+ /* TODO: Make ${ENVAR} expansion */
+ str = (*e)->NewStringUTF(e, J2S(val));
+
+ TCN_FREE_CSTRING(val);
+ return str;
+}
+
+TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
+{
+ const char *d;
+ TCN_ALLOC_CSTRING(domain);
+
+ UNREFERENCED(o);
+ if ((d = J2S(domain)) == NULL)
+ d = LOG_MSG_DOMAIN;
+
+ openlog(d, LOG_CONS | LOG_PID, LOG_LOCAL0);
+ TCN_FREE_CSTRING(domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
+ jstring msg)
+{
+ TCN_ALLOC_CSTRING(msg);
+ int id = LOG_DEBUG;
+ UNREFERENCED(o);
+
+ switch (level) {
+ case TCN_LOG_EMERG:
+ id = LOG_EMERG;
+ break;
+ case TCN_LOG_ERROR:
+ id = LOG_ERR;
+ break;
+ case TCN_LOG_NOTICE:
+ id = LOG_NOTICE;
+ break;
+ case TCN_LOG_WARN:
+ id = LOG_WARN;
+ break;
+ case TCN_LOG_INFO:
+ id = LOG_INFO;
+ break;
+ }
+ syslog (id, "%s", J2S(msg));
+
+ TCN_FREE_CSTRING(msg);
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** UNIX AF_LOCAL network wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision$, $Date$
+ */
+
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+/* ### should be tossed in favor of APR */
+#include <sys/stat.h>
+#include <sys/un.h> /* for sockaddr_un */
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t uxp_created = 0;
+static volatile apr_uint32_t uxp_closed = 0;
+static volatile apr_uint32_t uxp_cleared = 0;
+static volatile apr_uint32_t uxp_accepted = 0;
+
+void uxp_network_dump_statistics()
+{
+ fprintf(stderr, "NT Network Statistics ..\n");
+ fprintf(stderr, "Sockets created : %d\n", uxp_created);
+ fprintf(stderr, "Sockets accepted : %d\n", uxp_accepted);
+ fprintf(stderr, "Sockets closed : %d\n", uxp_closed);
+ fprintf(stderr, "Sockets cleared : %d\n", uxp_cleared);
+}
+
+#endif
+
+#define DEFNAME "/var/run/tomcatnativesock"
+#define DEFNAME_FMT "/var/run/tomcatnativesock%08x%08x"
+#define DEFSIZE 8192
+#define DEFTIMEOUT 60000
+
+#define TCN_UXP_UNKNOWN 0
+#define TCN_UXP_CLIENT 1
+#define TCN_UXP_ACCEPTED 2
+#define TCN_UXP_SERVER 3
+
+#define TCN_UNIX_MAXPATH 1024
+typedef struct {
+ apr_pool_t *pool;
+ apr_socket_t *sock; /* APR socket */
+ int sd;
+ struct sockaddr_un uxaddr;
+ int timeout;
+ int mode; /* Client or server mode */
+ char name[TCN_UNIX_MAXPATH+1];
+} tcn_uxp_conn_t;
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+ if (t < 0)
+ con->timeout = -1;
+ else
+ con->timeout = (int)(apr_time_as_msec(t));
+ return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t*)sock;
+ if (con->timeout < 0)
+ *t = -1;
+ else
+ *t = con->timeout * 1000;
+ return APR_SUCCESS;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+uxp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+ return apr_socket_opt_set(con->sock, opt, on);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+uxp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+ return apr_socket_opt_get(con->sock, opt, on);
+}
+
+static apr_status_t uxp_cleanup(void *data)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)data;
+
+ if (con) {
+ if (con->sock) {
+ apr_socket_close(con->sock);
+ con->sock = NULL;
+ }
+ if (con->mode == TCN_UXP_SERVER) {
+ unlink(con->name);
+ con->mode = TCN_UXP_UNKNOWN;
+ }
+ }
+
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&uxp_cleared);
+#endif
+ return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+ return apr_socket_shutdown(con->sock, how);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_close(apr_socket_t *sock)
+{
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&uxp_closed);
+#endif
+ return uxp_cleanup(sock);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+ return apr_socket_recv(con->sock, buf, len);
+}
+
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_send(apr_socket_t *sock, const char *buf,
+ apr_size_t *len)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+ return apr_socket_send(con->sock, buf, len);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_sendv(apr_socket_t *sock,
+ const struct iovec *vec,
+ apr_int32_t nvec, apr_size_t *len)
+{
+ tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+ return apr_socket_sendv(con->sock, vec, nvec, len);
+}
+
+static apr_status_t uxp_socket_cleanup(void *data)
+{
+ tcn_socket_t *s = (tcn_socket_t *)data;
+
+ if (s->net->cleanup) {
+ (*s->net->cleanup)(s->opaque);
+ s->net->cleanup = NULL;
+ }
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&uxp_cleared);
+#endif
+ return APR_SUCCESS;
+}
+
+static tcn_nlayer_t uxp_socket_layer = {
+ TCN_SOCKET_UNIX,
+ uxp_cleanup,
+ uxp_socket_close,
+ uxp_socket_shutdown,
+ uxp_socket_opt_get,
+ uxp_socket_opt_set,
+ uxp_socket_timeout_get,
+ uxp_socket_timeout_set,
+ uxp_socket_send,
+ uxp_socket_sendv,
+ uxp_socket_recv
+};
+
+TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ tcn_socket_t *s = NULL;
+ tcn_uxp_conn_t *con = NULL;
+ int sd;
+ TCN_ALLOC_CSTRING(name);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+ tcn_ThrowAPRException(e, apr_get_netos_error());
+ return 0;
+ }
+#ifdef TCN_DO_STATISTICS
+ uxp_created++;
+#endif
+ con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t));
+ con->pool = p;
+ con->mode = TCN_UXP_UNKNOWN;
+ con->timeout = DEFTIMEOUT;
+ con->sd = sd;
+ con->uxaddr.sun_family = AF_UNIX;
+ if (J2S(name)) {
+ strcpy(con->uxaddr.sun_path, J2S(name));
+ TCN_FREE_CSTRING(name);
+ }
+ else
+ strcpy(con->uxaddr.sun_path, DEFNAME);
+ s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+ s->pool = p;
+ s->net = &uxp_socket_layer;
+ s->opaque = con;
+ apr_pool_cleanup_register(p, (const void *)s,
+ uxp_socket_cleanup,
+ apr_pool_cleanup_null);
+
+ apr_os_sock_put(&(con->sock), &(con->sd), p);
+
+ return P2J(s);
+
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock,
+ jlong sa)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED_STDARGS;
+ UNREFERENCED(sa);
+ TCN_ASSERT(sock != 0);
+ if (s->net->type == TCN_SOCKET_UNIX) {
+ int rc;
+ tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+ c->mode = TCN_UXP_SERVER;
+ rc = bind(c->sd, (struct sockaddr *)&(c->uxaddr), sizeof(c->uxaddr));
+ if (rc < 0)
+ return errno;
+ else
+ return APR_SUCCESS;
+ }
+ else
+ return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock,
+ jint backlog)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED_STDARGS;
+
+ TCN_ASSERT(sock != 0);
+ if (s->net->type == TCN_SOCKET_UNIX) {
+ tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+ c->mode = TCN_UXP_SERVER;
+ return apr_socket_listen(c->sock, (apr_int32_t)backlog);
+ }
+ else
+ return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_pool_t *p = NULL;
+ tcn_socket_t *a = NULL;
+ tcn_uxp_conn_t *con = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+ if (s->net->type == TCN_SOCKET_UNIX) {
+ apr_socklen_t len;
+ tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+ con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t));
+ con->pool = p;
+ con->mode = TCN_UXP_ACCEPTED;
+ con->timeout = c->timeout;
+ len = sizeof(c->uxaddr);
+ /* Block until a client connects */
+ con->sd = accept(c->sd, (struct sockaddr *)&(con->uxaddr), &len);
+ if (con->sd < 0) {
+ tcn_ThrowAPRException(e, apr_get_os_error());
+ goto cleanup;
+ }
+ }
+ else {
+ tcn_ThrowAPRException(e, APR_ENOTIMPL);
+ goto cleanup;
+ }
+ if (con) {
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&uxp_accepted);
+#endif
+ a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+ a->pool = p;
+ a->net = &uxp_socket_layer;
+ a->opaque = con;
+ apr_pool_cleanup_register(p, (const void *)a,
+ uxp_socket_cleanup,
+ apr_pool_cleanup_null);
+ apr_os_sock_put(&(con->sock), &(con->sd), p);
+ }
+ return P2J(a);
+cleanup:
+ if (p)
+ apr_pool_destroy(p);
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock,
+ jlong sa)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ tcn_uxp_conn_t *con = NULL;
+ int rc;
+
+ UNREFERENCED(o);
+ UNREFERENCED(sa);
+ TCN_ASSERT(sock != 0);
+ if (s->net->type != TCN_SOCKET_UNIX)
+ return APR_ENOTSOCK;
+ con = (tcn_uxp_conn_t *)s->opaque;
+ if (con->mode != TCN_UXP_UNKNOWN)
+ return APR_EINVAL;
+ do {
+ rc = connect(con->sd, (const struct sockaddr *)&(con->uxaddr),
+ sizeof(con->uxaddr));
+ } while (rc == -1 && errno == EINTR);
+
+ if (rc == -1 && errno != EISCONN)
+ return errno;
+ con->mode = TCN_UXP_CLIENT;
+
+ return APR_SUCCESS;
+}
--- /dev/null
+#include <windows.h>
+
+LANGUAGE 0x9,0x1
+1 11 logmessages.bin
+
+#define TCN_COPYRIGHT "Copyright 2000-2006 The Apache Software " \
+ "Foundation or its licensors, as applicable."
+
+#define TCN_LICENSE "Licensed 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\r\n\r\n" \
+ "http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n" \
+ "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."
+
+#define TCN_VERISON "1.1.6"
+1000 ICON "apache.ico"
+
+1001 DIALOGEX 0, 0, 252, 51
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION
+CAPTION "Password prompt"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+ ICON 1000,-1,8,6,21,20
+ LTEXT "Some of your private key files are encrypted for security reasons.\nIn order to read them you have to provide the pass phrases.",
+ -1,29,5,220,19
+ LTEXT "Enter password:",-1,7,28,75,8
+ EDITTEXT 1002,67,27,174,12,ES_PASSWORD | ES_AUTOHSCROLL
+END
+
+1 VERSIONINFO
+ FILEVERSION 1,1,6,0
+ PRODUCTVERSION 1,1,6,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "Comments", TCN_LICENSE "\0"
+ VALUE "CompanyName", "Apache Software Foundation\0"
+ VALUE "FileDescription", "Tomcat Native Java Library\0"
+ VALUE "FileVersion", TCN_VERISON "\0"
+ VALUE "InternalName", "libtcnative-1\0"
+ VALUE "LegalCopyright", TCN_COPYRIGHT "\0"
+ VALUE "OriginalFilename", "libtcnative-1.dll\0"
+ VALUE "ProductName", "Tomcat Native Java Library\0"
+ VALUE "ProductVersion", TCN_VERISON "\0"
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
--- /dev/null
+MessageId=0x1
+Severity=Error
+SymbolicName=LOG_MSG_EMERG
+Language=English
+Emerg: %1
+.
+
+MessageId=0x2
+Severity=Error
+SymbolicName=LOG_MSG_ERROR
+Language=English
+Error: %1
+.
+
+MessageId=0x3
+Severity=Warning
+SymbolicName=LOG_MSG_NOTICE
+Language=English
+Notice: %1
+.
+
+MessageId=0x4
+Severity=Warning
+SymbolicName=LOG_MSG_WARN
+Language=English
+Warn: %1
+.
+
+MessageId=0x5
+Severity=Informational
+SymbolicName=LOG_MSG_INFO
+Language=English
+Info: %1
+.
+
+MessageId=0x6
+Severity=Success
+SymbolicName=LOG_MSG_DEBUG
+Language=English
+Debug: %1
+.
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** NT Pipes network wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision$, $Date$
+ */
+
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#define STRICT
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <sddl.h>
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t ntp_created = 0;
+static volatile apr_uint32_t ntp_closed = 0;
+static volatile apr_uint32_t ntp_cleared = 0;
+static volatile apr_uint32_t ntp_accepted = 0;
+
+void ntp_network_dump_statistics()
+{
+ fprintf(stderr, "NT Network Statistics ..\n");
+ fprintf(stderr, "Sockets created : %d\n", ntp_created);
+ fprintf(stderr, "Sockets accepted : %d\n", ntp_accepted);
+ fprintf(stderr, "Sockets closed : %d\n", ntp_closed);
+ fprintf(stderr, "Sockets cleared : %d\n", ntp_cleared);
+}
+
+#endif
+
+#define DEFNAME "\\\\.\\PIPE\\TOMCATNATIVEPIPE"
+#define DEFNAME_FMT "\\\\.\\PIPE\\TOMCATNATIVEPIPE%08X%08X"
+#define DEFSIZE 8192
+#define DEFTIMEOUT 60000
+
+#define TCN_NTP_UNKNOWN 0
+#define TCN_NTP_CLIENT 1
+#define TCN_NTP_SERVER 2
+
+typedef struct {
+ apr_pool_t *pool;
+ apr_socket_t *sock; /* Dummy socket */
+ OVERLAPPED rd_o;
+ OVERLAPPED wr_o;
+ HANDLE h_pipe;
+ HANDLE rd_event;
+ HANDLE wr_event;
+ DWORD timeout;
+ int mode; /* Client or server mode */
+ int nmax;
+ DWORD sndbuf;
+ DWORD rcvbuf;
+ char name[MAX_PATH+1];
+ SECURITY_ATTRIBUTES sa;
+} tcn_ntp_conn_t;
+
+static const char *NTSD_STRING = "D:" /* Discretionary ACL */
+ "(D;OICI;GA;;;BG)" /* Deny access to Built-in Guests */
+ "(D;OICI;GA;;;AN)" /* Deny access to Anonymous Logon */
+ "(A;OICI;GRGWGX;;;AU)" /* Allow read/write/execute to Authenticated Users */
+ "(A;OICI;GA;;;BA)" /* Allow full control to Administrators */
+ "(A;OICI;GA;;;LS)" /* Allow full control to Local service account */
+ "(A;OICI;GA;;;SY)"; /* Allow full control to Local system */
+
+
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+ if (t < 0)
+ con->timeout = INFINITE;
+ else
+ con->timeout = (DWORD)(apr_time_as_msec(t));
+ return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t*)sock;
+ if (con->timeout == INFINITE)
+ *t = -1;
+ else
+ *t = con->timeout * 1000;
+ return APR_SUCCESS;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ntp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+ apr_status_t rv = APR_SUCCESS;
+ switch (opt) {
+ case APR_SO_SNDBUF:
+ con->sndbuf = (DWORD)on;
+ break;
+ case APR_SO_RCVBUF:
+ con->rcvbuf = (DWORD)on;
+ break;
+ default:
+ rv = APR_EINVAL;
+ break;
+ }
+ return rv;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ntp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+ apr_status_t rv = APR_SUCCESS;
+ switch (opt) {
+ case APR_SO_SNDBUF:
+ *on = con->sndbuf;
+ break;
+ case APR_SO_RCVBUF:
+ *on = con->rcvbuf;
+ break;
+ default:
+ rv = APR_EINVAL;
+ break;
+ }
+ return rv;
+}
+
+static apr_status_t ntp_cleanup(void *data)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)data;
+
+ if (con) {
+ if (con->h_pipe) {
+ FlushFileBuffers(con->h_pipe);
+ CloseHandle(con->h_pipe);
+ con->h_pipe = NULL;
+ }
+ if (con->rd_event) {
+ CloseHandle(con->rd_event);
+ con->rd_event = NULL;
+ }
+ if (con->wr_event) {
+ CloseHandle(con->wr_event);
+ con->wr_event= NULL;
+ }
+ }
+
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&ntp_cleared);
+#endif
+ return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+ UNREFERENCED(how);
+ return ntp_cleanup(sock);;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_close(apr_socket_t *sock)
+{
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&ntp_closed);
+#endif
+ return ntp_cleanup(sock);;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+ DWORD readed;
+
+ if (!ReadFile(con->h_pipe, buf, *len, &readed, &con->rd_o)) {
+ DWORD err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ DWORD r = WaitForSingleObject(con->rd_event, con->timeout);
+ if (r == WAIT_TIMEOUT)
+ return APR_TIMEUP;
+ else if (r != WAIT_OBJECT_0)
+ return APR_EOF;
+ }
+ else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) {
+ /* Server closed the pipe */
+ return APR_EOF;
+ }
+ GetOverlappedResult(con->h_pipe, &con->rd_o, &readed, FALSE);
+ }
+ *len = readed;
+ return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_send(apr_socket_t *sock, const char *buf,
+ apr_size_t *len)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+ DWORD written;
+
+ if (!WriteFile(con->h_pipe, buf, *len, &written, &con->wr_o)) {
+ DWORD err = GetLastError();
+ if (err == ERROR_IO_PENDING) {
+ DWORD r = WaitForSingleObject(con->wr_event, con->timeout);
+ if (r == WAIT_TIMEOUT)
+ return APR_TIMEUP;
+ else if (r != WAIT_OBJECT_0)
+ return APR_EOF;
+ }
+ else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) {
+ /* Server closed the pipe */
+ return APR_EOF;
+ }
+ GetOverlappedResult(con->h_pipe, &con->wr_o, &written, FALSE);
+ }
+ *len = written;
+ return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_sendv(apr_socket_t *sock,
+ const struct iovec *vec,
+ apr_int32_t nvec, apr_size_t *len)
+{
+ tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+ apr_status_t rv;
+ apr_size_t written = 0;
+ apr_int32_t i;
+
+ for (i = 0; i < nvec; i++) {
+ apr_size_t rd = vec[i].iov_len;
+ if ((rv = ntp_socket_send((apr_socket_t *)con,
+ vec[i].iov_base, &rd)) != APR_SUCCESS) {
+ *len = written;
+ return rv;
+ }
+ written += rd;
+ }
+ *len = written;
+ return APR_SUCCESS;
+}
+
+static apr_status_t ntp_socket_cleanup(void *data)
+{
+ tcn_socket_t *s = (tcn_socket_t *)data;
+
+ if (s->net->cleanup) {
+ (*s->net->cleanup)(s->opaque);
+ s->net->cleanup = NULL;
+ }
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&ntp_cleared);
+#endif
+ return APR_SUCCESS;
+}
+
+static tcn_nlayer_t ntp_socket_layer = {
+ TCN_SOCKET_NTPIPE,
+ ntp_cleanup,
+ ntp_socket_close,
+ ntp_socket_shutdown,
+ ntp_socket_opt_get,
+ ntp_socket_opt_set,
+ ntp_socket_timeout_get,
+ ntp_socket_timeout_set,
+ ntp_socket_send,
+ ntp_socket_sendv,
+ ntp_socket_recv
+};
+
+static BOOL create_DACL(LPSECURITY_ATTRIBUTES psa)
+{
+
+ return ConvertStringSecurityDescriptorToSecurityDescriptor(
+ NTSD_STRING,
+ SDDL_REVISION_1,
+ &(psa->lpSecurityDescriptor),
+ NULL);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ tcn_socket_t *s = NULL;
+ tcn_ntp_conn_t *con = NULL;
+ TCN_ALLOC_CSTRING(name);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+#ifdef TCN_DO_STATISTICS
+ ntp_created++;
+#endif
+ con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t));
+ con->pool = p;
+ con->mode = TCN_NTP_UNKNOWN;
+ con->nmax = PIPE_UNLIMITED_INSTANCES;
+ con->timeout = DEFTIMEOUT;
+ con->sndbuf = DEFSIZE;
+ con->rcvbuf = DEFSIZE;
+ if (J2S(name)) {
+ strncpy(con->name, J2S(name), MAX_PATH);
+ con->name[MAX_PATH] = '\0';
+ TCN_FREE_CSTRING(name);
+ }
+ else
+ strcpy(con->name, DEFNAME);
+ con->sa.nLength = sizeof(con->sa);
+ con->sa.bInheritHandle = TRUE;
+ if (!create_DACL(&con->sa)) {
+ tcn_ThrowAPRException(e, apr_get_os_error());
+ return 0;
+ }
+
+ s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+ s->pool = p;
+ s->net = &ntp_socket_layer;
+ s->opaque = con;
+ apr_pool_cleanup_register(p, (const void *)s,
+ ntp_socket_cleanup,
+ apr_pool_cleanup_null);
+
+ fflush(stderr);
+ return P2J(s);
+
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock,
+ jlong sa)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED_STDARGS;
+ UNREFERENCED(sa);
+ TCN_ASSERT(sock != 0);
+ if (s->net->type == TCN_SOCKET_NTPIPE) {
+ tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+ c->mode = TCN_NTP_SERVER;
+ return APR_SUCCESS;
+ }
+ else
+ return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock,
+ jint backlog)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED_STDARGS;
+
+ TCN_ASSERT(sock != 0);
+ if (s->net->type == TCN_SOCKET_NTPIPE) {
+ tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+ c->mode = TCN_NTP_SERVER;
+ if (backlog > 0)
+ c->nmax = backlog;
+ else
+ c->nmax = PIPE_UNLIMITED_INSTANCES;
+ return APR_SUCCESS;
+ }
+ else
+ return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_pool_t *p = NULL;
+ tcn_socket_t *a = NULL;
+ tcn_ntp_conn_t *con = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+ if (s->net->type == TCN_SOCKET_NTPIPE) {
+ tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+ con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t));
+ con->pool = p;
+ con->mode = TCN_NTP_SERVER;
+ con->nmax = c->nmax;
+ con->timeout = c->timeout;
+ strcpy(con->name, c->name);
+ con->h_pipe = CreateNamedPipe(con->name,
+ PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+ PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+ con->nmax,
+ con->sndbuf,
+ con->rcvbuf,
+ con->timeout,
+ &c->sa);
+ if (con->h_pipe == INVALID_HANDLE_VALUE) {
+ tcn_ThrowAPRException(e, apr_get_os_error());
+ goto cleanup;
+ }
+ /* Block until a client connects */
+ if (!ConnectNamedPipe(con->h_pipe, NULL)) {
+ DWORD err = GetLastError();
+ if (err != ERROR_PIPE_CONNECTED) {
+ CloseHandle(con->h_pipe);
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(err));
+ goto cleanup;
+ }
+ }
+ /* Create overlapped events */
+ con->rd_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ con->rd_o.hEvent = con->rd_event;
+ con->wr_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ con->wr_o.hEvent = con->wr_event;
+ }
+ else {
+ tcn_ThrowAPRException(e, APR_ENOTIMPL);
+ goto cleanup;
+ }
+ if (con) {
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&ntp_accepted);
+#endif
+ a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+ a->pool = p;
+ a->net = &ntp_socket_layer;
+ a->opaque = con;
+ apr_pool_cleanup_register(p, (const void *)a,
+ ntp_socket_cleanup,
+ apr_pool_cleanup_null);
+ }
+ return P2J(a);
+cleanup:
+ if (p)
+ apr_pool_destroy(p);
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock,
+ jlong sa)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_pool_t *p = NULL;
+ tcn_socket_t *a = NULL;
+ tcn_ntp_conn_t *con = NULL;
+
+ UNREFERENCED(o);
+ UNREFERENCED(sa);
+ TCN_ASSERT(sock != 0);
+ if (s->net->type != TCN_SOCKET_NTPIPE)
+ return APR_ENOTSOCK;
+ con = (tcn_ntp_conn_t *)s->opaque;
+ if (con->mode == TCN_NTP_SERVER)
+ return APR_EINVAL;
+ con->mode = TCN_NTP_CLIENT;
+
+ while (TRUE) {
+ con->h_pipe = CreateFile(con->name,
+ GENERIC_WRITE | GENERIC_READ,
+ FILE_SHARE_READ | FILE_SHARE_WRITE ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_FLAG_OVERLAPPED,
+ NULL);
+ if (con->h_pipe != INVALID_HANDLE_VALUE)
+ break;
+ if (GetLastError() == ERROR_PIPE_BUSY) {
+ /* All pipe instances are busy, so wait for
+ * timeout value specified by the server process in
+ * the CreateNamedPipe function.
+ */
+ if (!WaitNamedPipe(con->name, NMPWAIT_USE_DEFAULT_WAIT))
+ return apr_get_os_error();
+ }
+ else
+ return apr_get_os_error();
+ }
+
+ /* Create overlapped events */
+ con->rd_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ con->rd_o.hEvent = con->rd_event;
+ con->wr_event = CreateEvent(NULL, TRUE, FALSE, NULL);
+ con->wr_o.hEvent = con->wr_event;
+
+ return APR_SUCCESS;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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$
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <shlwapi.h>
+
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_arch_misc.h" /* for apr_os_level */
+#include "apr_arch_atime.h" /* for FileTimeToAprTime */
+
+#include "tcn.h"
+
+#define SAFE_CLOSE_KEY(k) \
+ if ((k) != NULL && (k) != INVALID_HANDLE_VALUE) { \
+ RegCloseKey((k)); \
+ (k) = NULL; \
+ }
+
+typedef struct {
+ apr_pool_t *pool;
+ HKEY root;
+ HKEY key;
+} tcn_nt_registry_t;
+
+
+#define TCN_HKEY_CLASSES_ROOT 1
+#define TCN_HKEY_CURRENT_CONFIG 2
+#define TCN_HKEY_CURRENT_USER 3
+#define TCN_HKEY_LOCAL_MACHINE 4
+#define TCN_HKEY_USERS 5
+
+static const struct {
+ HKEY k;
+} TCN_KEYS[] = {
+ INVALID_HANDLE_VALUE,
+ HKEY_CLASSES_ROOT,
+ HKEY_CURRENT_CONFIG,
+ HKEY_CURRENT_USER,
+ HKEY_LOCAL_MACHINE,
+ HKEY_USERS,
+ INVALID_HANDLE_VALUE
+};
+
+#define TCN_KEY_ALL_ACCESS 0x0001
+#define TCN_KEY_CREATE_LINK 0x0002
+#define TCN_KEY_CREATE_SUB_KEY 0x0004
+#define TCN_KEY_ENUMERATE_SUB_KEYS 0x0008
+#define TCN_KEY_EXECUTE 0x0010
+#define TCN_KEY_NOTIFY 0x0020
+#define TCN_KEY_QUERY_VALUE 0x0040
+#define TCN_KEY_READ 0x0080
+#define TCN_KEY_SET_VALUE 0x0100
+#define TCN_KEY_WOW64_64KEY 0x0200
+#define TCN_KEY_WOW64_32KEY 0x0400
+#define TCN_KEY_WRITE 0x0800
+
+#define TCN_REGSAM(s, x) \
+ s = 0; \
+ if (x & TCN_KEY_ALL_ACCESS) \
+ s |= KEY_ALL_ACCESS; \
+ if (x & TCN_KEY_CREATE_LINK) \
+ s |= KEY_CREATE_LINK; \
+ if (x & TCN_KEY_CREATE_SUB_KEY) \
+ s |= KEY_CREATE_SUB_KEY; \
+ if (x & TCN_KEY_ENUMERATE_SUB_KEYS) \
+ s |= KEY_ENUMERATE_SUB_KEYS; \
+ if (x & TCN_KEY_EXECUTE) \
+ s |= KEY_EXECUTE; \
+ if (x & TCN_KEY_NOTIFY) \
+ s |= KEY_NOTIFY; \
+ if (x & TCN_KEY_READ) \
+ s |= KEY_READ; \
+ if (x & TCN_KEY_SET_VALUE) \
+ s |= KEY_SET_VALUE; \
+ if (x & TCN_KEY_WOW64_64KEY) \
+ s |= KEY_WOW64_64KEY; \
+ if (x & TCN_KEY_WOW64_32KEY) \
+ s |= KEY_WOW64_32KEY; \
+ if (x & TCN_KEY_WRITE) \
+ s |= KEY_WRITE
+
+#define TCN_REG_BINARY 1
+#define TCN_REG_DWORD 2
+#define TCN_REG_EXPAND_SZ 3
+#define TCN_REG_MULTI_SZ 4
+#define TCN_REG_QWORD 5
+#define TCN_REG_SZ 6
+
+static const struct {
+ DWORD t;
+} TCN_REGTYPES[] = {
+ REG_NONE,
+ REG_BINARY,
+ REG_DWORD,
+ REG_EXPAND_SZ,
+ REG_MULTI_SZ,
+ REG_QWORD,
+ REG_SZ,
+ REG_NONE
+};
+
+static apr_status_t registry_cleanup(void *data)
+{
+ tcn_nt_registry_t *reg = (tcn_nt_registry_t *)data;
+
+ if (reg) {
+ SAFE_CLOSE_KEY(reg->key);
+ }
+ return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, create)(TCN_STDARGS, jint root, jstring name,
+ jint sam, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ tcn_nt_registry_t *reg = NULL;
+ TCN_ALLOC_WSTRING(name);
+ HKEY key;
+ LONG rc;
+ REGSAM s;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+ tcn_ThrowException(e, "Invalid Registry Root Key");
+ goto cleanup;
+ }
+ if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
+ tcn_ThrowException(e, "Invalid Registry Key Security");
+ goto cleanup;
+ }
+ reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
+ reg->pool = p;
+ reg->root = TCN_KEYS[root].k;
+ reg->key = NULL;
+ TCN_INIT_WSTRING(name);
+ TCN_REGSAM(s, sam);
+ rc = RegCreateKeyExW(reg->root, J2W(name), 0, NULL, REG_OPTION_NON_VOLATILE,
+ s, NULL, &key, NULL);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ reg->key = key;
+ apr_pool_cleanup_register(p, (const void *)reg,
+ registry_cleanup,
+ apr_pool_cleanup_null);
+
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return P2J(reg);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, open)(TCN_STDARGS, jint root, jstring name,
+ jint sam, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ tcn_nt_registry_t *reg = NULL;
+ TCN_ALLOC_WSTRING(name);
+ HKEY key;
+ LONG rc;
+ REGSAM s;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+ tcn_ThrowException(e, "Invalid Registry Root Key");
+ goto cleanup;
+ }
+ if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
+ tcn_ThrowException(e, "Invalid Registry Key Security");
+ goto cleanup;
+ }
+ reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
+ reg->pool = p;
+ reg->root = TCN_KEYS[root].k;
+ reg->key = NULL;
+ TCN_INIT_WSTRING(name);
+ TCN_REGSAM(s, sam);
+ rc = RegOpenKeyExW(reg->root, J2W(name), 0, s, &key);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ reg->key = key;
+ apr_pool_cleanup_register(p, (const void *)reg,
+ registry_cleanup,
+ apr_pool_cleanup_null);
+
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return P2J(reg);
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, close)(TCN_STDARGS, jlong reg)
+{
+ tcn_nt_registry_t *r = J2P(reg, tcn_nt_registry_t *);
+ UNREFERENCED_STDARGS;
+
+ TCN_ASSERT(reg != 0);
+
+ registry_cleanup(r);
+ apr_pool_cleanup_kill(r->pool, r, registry_cleanup);
+ return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getType)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD v;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, &v, NULL, NULL);
+ if (rc != ERROR_SUCCESS)
+ v = -rc;
+ TCN_FREE_WSTRING(name);
+ switch (v) {
+ case REG_BINARY:
+ v = TCN_REG_BINARY;
+ break;
+ case REG_DWORD:
+ v = TCN_REG_DWORD;
+ break;
+ case REG_EXPAND_SZ:
+ v = TCN_REG_EXPAND_SZ;
+ break;
+ case REG_MULTI_SZ:
+ v = TCN_REG_MULTI_SZ;
+ break;
+ case REG_QWORD:
+ v = TCN_REG_QWORD;
+ break;
+ case REG_SZ:
+ v = TCN_REG_SZ;
+ break;
+ case REG_DWORD_BIG_ENDIAN:
+ v = 0;
+ break;
+ }
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getSize)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD v;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, NULL, &v);
+ if (rc != ERROR_SUCCESS)
+ v = -rc;
+ TCN_FREE_WSTRING(name);
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getValueI)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD t, l;
+ DWORD v = 0;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ if (t == REG_DWORD) {
+ l = sizeof(DWORD);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ }
+ else if (t == REG_SZ || t == REG_BINARY ||
+ t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
+ v = l;
+ else {
+ v = 0;
+ tcn_ThrowException(e, "Unable to convert the value to integer");
+ }
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, getValueJ)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD t, l;
+ UINT64 v = 0;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ if (t == REG_DWORD) {
+ DWORD tv;
+ l = sizeof(DWORD);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&tv, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ v = tv;
+ }
+ else if (t == REG_QWORD) {
+ l = sizeof(UINT64);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ }
+ else if (t == REG_SZ || t == REG_BINARY ||
+ t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
+ v = l;
+ else {
+ v = 0;
+ tcn_ThrowException(e, "Unable to convert the value to long");
+ }
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Registry, getValueS)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD t, l;
+ jstring v = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ if (t == REG_SZ || t == REG_EXPAND_SZ) {
+ jchar *vw = (jchar *)malloc(l);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ free(vw);
+ goto cleanup;
+ }
+ v = (*e)->NewString((e), vw, wcslen(vw));
+ free(vw);
+ }
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jbyteArray, Registry, getValueB)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD t, l;
+ jbyteArray v = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ if (t == REG_BINARY) {
+ BYTE *b = (BYTE *)malloc(l);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, b, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ free(b);
+ goto cleanup;
+ }
+ v = tcn_new_arrayb(e, b, l);
+ free(b);
+ }
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return v;
+}
+
+static jsize get_multi_sz_count(LPCWSTR str)
+{
+ LPCWSTR p = str;
+ jsize cnt = 0;
+ for ( ; p && *p; p++) {
+ cnt++;
+ while (*p)
+ p++;
+ }
+ return cnt;
+}
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, getValueA)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD t, l;
+ jobjectArray v = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ if (t == REG_MULTI_SZ) {
+ jsize cnt = 0;
+ jchar *p;
+ jchar *vw = (jchar *)malloc(l);
+ rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ free(vw);
+ goto cleanup;
+ }
+ cnt = get_multi_sz_count(vw);
+ if (cnt) {
+ jsize idx = 0;
+ v = tcn_new_arrays(e, cnt);
+ for (p = vw ; p && *p; p++) {
+ jstring s;
+ jchar *b = p;
+ while (*p)
+ p++;
+ s = (*e)->NewString((e), b, (jsize)(p - b));
+ (*e)->SetObjectArrayElement((e), v, idx++, s);
+ }
+ }
+ free(vw);
+ }
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueI)(TCN_STDARGS, jlong key,
+ jstring name, jint val)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ DWORD v = (DWORD)val;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegSetValueExW(k->key, J2W(name), 0, REG_DWORD, (CONST BYTE *)&v, sizeof(DWORD));
+ TCN_FREE_WSTRING(name);
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueJ)(TCN_STDARGS, jlong key,
+ jstring name, jlong val)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ UINT64 v = (UINT64)val;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ rc = RegSetValueExW(k->key, J2W(name), 0, REG_QWORD, (CONST BYTE *)&v, sizeof(UINT64));
+ TCN_FREE_WSTRING(name);
+ return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueS)(TCN_STDARGS, jlong key,
+ jstring name, jstring val)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ TCN_ALLOC_WSTRING(val);
+ LONG rc;
+ DWORD len;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ TCN_INIT_WSTRING(val);
+ len = wcslen(J2W(val));
+ rc = RegSetValueExW(k->key, J2W(name), 0, REG_SZ,
+ (CONST BYTE *)J2W(val), (len + 1) * 2);
+ TCN_FREE_WSTRING(name);
+ TCN_FREE_WSTRING(val);
+ return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueE)(TCN_STDARGS, jlong key,
+ jstring name, jstring val)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ TCN_ALLOC_WSTRING(val);
+ LONG rc;
+ DWORD len;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ TCN_INIT_WSTRING(val);
+ len = wcslen(J2W(val));
+ rc = RegSetValueExW(k->key, J2W(name), 0, REG_EXPAND_SZ,
+ (CONST BYTE *)J2W(val), (len + 1) * 2);
+ TCN_FREE_WSTRING(name);
+ TCN_FREE_WSTRING(val);
+ return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueA)(TCN_STDARGS, jlong key,
+ jstring name,
+ jobjectArray vals)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ LONG rc;
+ jsize i, len;
+ jsize sl = 0;
+ jchar *msz, *p;
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ TCN_INIT_WSTRING(name);
+ len = (*e)->GetArrayLength((e), vals);
+ for (i = 0; i < len; i++) {
+ jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
+ sl += (*e)->GetStringLength((e), s) + 1;
+ }
+ sl = (sl + 1) * 2;
+ p = msz = (jchar *)calloc(1, sl);
+ for (i = 0; i < len; i++) {
+ jsize l;
+ jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
+ l = (*e)->GetStringLength((e), s);
+ wcsncpy(p, (*e)->GetStringChars(e, s, 0), l);
+ p += l + 1;
+ }
+ rc = RegSetValueExW(k->key, J2W(name), 0, REG_MULTI_SZ,
+ (CONST BYTE *)msz, sl);
+ TCN_FREE_WSTRING(name);
+ free(msz);
+ return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueB)(TCN_STDARGS, jlong key,
+ jstring name,
+ jbyteArray val)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ TCN_ALLOC_WSTRING(name);
+ jsize nbytes = (*e)->GetArrayLength(e, val);
+ jbyte *bytes = (*e)->GetByteArrayElements(e, val, NULL);
+ LONG rc;
+
+ rc = RegSetValueExW(k->key, J2W(name), 0, REG_BINARY,
+ bytes, (DWORD)nbytes);
+ (*e)->ReleaseByteArrayElements(e, val, bytes, JNI_ABORT);
+ TCN_FREE_WSTRING(name);
+ return rc;
+}
+
+#define MAX_VALUE_NAME 4096
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumKeys)(TCN_STDARGS, jlong key)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ LONG rc;
+ jobjectArray v = NULL;
+ jsize cnt = 0;
+
+ WCHAR achKey[MAX_PATH];
+ WCHAR achClass[MAX_PATH] = L"";
+ DWORD cchClassName = MAX_PATH;
+ DWORD cSubKeys;
+ DWORD cbMaxSubKey;
+ DWORD cchMaxClass;
+ DWORD cValues;
+ DWORD cchMaxValue;
+ DWORD cbMaxValueData;
+ DWORD cbSecurityDescriptor;
+ FILETIME ftLastWriteTime;
+
+ DWORD cchValue = MAX_VALUE_NAME;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ rc = RegQueryInfoKeyW(k->key,
+ achClass,
+ &cchClassName,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKey,
+ &cchMaxClass,
+ &cValues,
+ &cchMaxValue,
+ &cbMaxValueData,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ cnt = cSubKeys;
+ if (cnt) {
+ jsize idx = 0;
+ v = tcn_new_arrays(e, cnt);
+ for (idx = 0; idx < cnt; idx++) {
+ jstring s;
+ DWORD achKeyLen = MAX_PATH;
+ rc = RegEnumKeyExW(k->key,
+ idx,
+ achKey,
+ &achKeyLen,
+ NULL,
+ NULL,
+ NULL,
+ &ftLastWriteTime);
+ if (rc == (DWORD)ERROR_SUCCESS) {
+ s = (*e)->NewString((e), achKey, wcslen(achKey));
+ (*e)->SetObjectArrayElement((e), v, idx, s);
+ }
+ }
+ }
+cleanup:
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumValues)(TCN_STDARGS, jlong key)
+{
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+ LONG rc;
+ jobjectArray v = NULL;
+ jsize cnt = 0;
+
+ WCHAR achClass[MAX_PATH] = L"";
+ DWORD cchClassName = MAX_PATH;
+ DWORD cSubKeys;
+ DWORD cbMaxSubKey;
+ DWORD cchMaxClass;
+ DWORD cValues;
+ DWORD cchMaxValue;
+ DWORD cbMaxValueData;
+ DWORD cbSecurityDescriptor;
+ FILETIME ftLastWriteTime;
+
+ WCHAR achValue[MAX_VALUE_NAME];
+ DWORD cchValue = MAX_VALUE_NAME;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(key != 0);
+ /* Get the class name and the value count. */
+ rc = RegQueryInfoKeyW(k->key,
+ achClass,
+ &cchClassName,
+ NULL,
+ &cSubKeys,
+ &cbMaxSubKey,
+ &cchMaxClass,
+ &cValues,
+ &cchMaxValue,
+ &cbMaxValueData,
+ &cbSecurityDescriptor,
+ &ftLastWriteTime);
+ if (rc != ERROR_SUCCESS) {
+ tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+ goto cleanup;
+ }
+ cnt = cValues;
+ if (cnt) {
+ jsize idx = 0;
+ v = tcn_new_arrays(e, cnt);
+ for (idx = 0; idx < cnt; idx++) {
+ jstring s;
+ cchValue = MAX_VALUE_NAME;
+ achValue[0] = '\0';
+ rc = RegEnumValueW(k->key, idx,
+ achValue,
+ &cchValue,
+ NULL,
+ NULL, // &dwType,
+ NULL, // &bData,
+ NULL); // &bcData
+ if (rc == (DWORD)ERROR_SUCCESS) {
+ s = (*e)->NewString((e), achValue, wcslen(achValue));
+ (*e)->SetObjectArrayElement((e), v, idx, s);
+ }
+ }
+ }
+cleanup:
+ return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, deleteKey)(TCN_STDARGS, jint root, jstring name,
+ jboolean only_if_empty)
+{
+ DWORD rv;
+ TCN_ALLOC_WSTRING(name);
+
+ UNREFERENCED(o);
+ if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+ rv = EBADF;
+ goto cleanup;
+ }
+ if (only_if_empty)
+ rv = SHDeleteEmptyKeyW(TCN_KEYS[root].k, J2W(name));
+ else
+ rv = SHDeleteKeyW(TCN_KEYS[root].k, J2W(name));
+cleanup:
+ TCN_FREE_WSTRING(name);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, deleteValue)(TCN_STDARGS, jlong key,
+ jstring name)
+{
+ LONG rv;
+ TCN_ALLOC_WSTRING(name);
+ tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+
+ UNREFERENCED(o);
+ rv = RegDeleteValueW(k->key, J2W(name));
+ TCN_FREE_WSTRING(name);
+ return (jint)rv;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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$
+ */
+
+#ifndef _WIN32_WINNT
+#define _WIN32_WINNT 0x0500
+#endif
+#include <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_poll.h"
+#include "apr_network_io.h"
+#include "apr_arch_misc.h" /* for apr_os_level */
+#include "apr_arch_atime.h" /* for FileTimeToAprTime */
+
+#include "tcn.h"
+#include "ssl_private.h"
+
+#pragma warning(push)
+#pragma warning(disable : 4201)
+#if (_WIN32_WINNT < 0x0501)
+#include <winternl.h>
+#endif
+#include <psapi.h>
+#pragma warning(pop)
+
+
+static CRITICAL_SECTION dll_critical_section; /* dll's critical section */
+static HINSTANCE dll_instance = NULL;
+static SYSTEM_INFO dll_system_info;
+static HANDLE h_kernel = NULL;
+static HANDLE h_ntdll = NULL;
+static char dll_file_name[MAX_PATH];
+
+typedef BOOL (WINAPI *pfnGetSystemTimes)(LPFILETIME, LPFILETIME, LPFILETIME);
+static pfnGetSystemTimes fnGetSystemTimes = NULL;
+#if (_WIN32_WINNT < 0x0501)
+typedef NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+static pfnNtQuerySystemInformation fnNtQuerySystemInformation = NULL;
+#endif
+
+BOOL
+WINAPI
+DllMain(
+ HINSTANCE instance,
+ DWORD reason,
+ LPVOID reserved)
+{
+
+ switch (reason) {
+ /** The DLL is loading due to process
+ * initialization or a call to LoadLibrary.
+ */
+ case DLL_PROCESS_ATTACH:
+ InitializeCriticalSection(&dll_critical_section);
+ dll_instance = instance;
+ GetSystemInfo(&dll_system_info);
+ if ((h_kernel = LoadLibrary("kernel32.dll")) != NULL)
+ fnGetSystemTimes = (pfnGetSystemTimes)GetProcAddress(h_kernel,
+ "GetSystemTimes");
+ if (fnGetSystemTimes == NULL) {
+ FreeLibrary(h_kernel);
+ h_kernel = NULL;
+#if (_WIN32_WINNT < 0x0501)
+ if ((h_ntdll = LoadLibrary("ntdll.dll")) != NULL)
+ fnNtQuerySystemInformation =
+ (pfnNtQuerySystemInformation)GetProcAddress(h_ntdll,
+ "NtQuerySystemInformation");
+
+ if (fnNtQuerySystemInformation == NULL) {
+ FreeLibrary(h_ntdll);
+ h_ntdll = NULL;
+ }
+#endif
+ }
+ GetModuleFileName(instance, dll_file_name, sizeof(dll_file_name));
+ break;
+ /** The attached process creates a new thread.
+ */
+ case DLL_THREAD_ATTACH:
+ break;
+
+ /** The thread of the attached process terminates.
+ */
+ case DLL_THREAD_DETACH:
+ break;
+
+ /** DLL unload due to process termination
+ * or FreeLibrary.
+ */
+ case DLL_PROCESS_DETACH:
+ /* Make sure the library is always terminated */
+ apr_terminate();
+ if (h_kernel)
+ FreeLibrary(h_kernel);
+ if (h_ntdll)
+ FreeLibrary(h_ntdll);
+ DeleteCriticalSection(&dll_critical_section);
+ break;
+
+ default:
+ break;
+ }
+
+ return TRUE;
+ UNREFERENCED_PARAMETER(reserved);
+}
+
+
+TCN_IMPLEMENT_CALL(jstring, OS, syserror)(TCN_STDARGS, jint err)
+{
+ jstring str;
+ void *buf;
+
+ UNREFERENCED(o);
+ if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR)&buf,
+ 0,
+ NULL)) {
+ str = AJP_TO_JSTRING("Unknown Error");
+ }
+ else {
+ str = AJP_TO_JSTRING((const char *)buf);
+ LocalFree(buf);
+ }
+ return str;
+}
+
+TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
+{
+ jstring str;
+ jchar buf[TCN_BUFFER_SZ] = L"";
+ DWORD len;
+ TCN_ALLOC_WSTRING(val);
+
+ UNREFERENCED(o);
+ TCN_INIT_WSTRING(val);
+
+ len = ExpandEnvironmentStringsW(J2W(val), buf, TCN_BUFFER_SZ - 1);
+ if (len > (TCN_BUFFER_SZ - 1)) {
+ jchar *dbuf = malloc((len + 1) * 2);
+ ExpandEnvironmentStringsW(J2W(val), dbuf, len);
+ str = (*e)->NewString(e, dbuf, wcslen(dbuf));
+ free(dbuf);
+ }
+ else
+ str = (*e)->NewString(e, buf, wcslen(buf));
+
+ TCN_FREE_WSTRING(val);
+ return str;
+}
+
+#define LOG_MSG_EMERG 0xC0000001L
+#define LOG_MSG_ERROR 0xC0000002L
+#define LOG_MSG_NOTICE 0x80000003L
+#define LOG_MSG_WARN 0x80000004L
+#define LOG_MSG_INFO 0x40000005L
+#define LOG_MSG_DEBUG 0x00000006L
+#define LOG_MSG_DOMAIN "Native"
+
+static char log_domain[MAX_PATH] = "Native";
+
+static void init_log_source(const char *domain)
+{
+ HKEY key;
+ DWORD ts;
+ char event_key[MAX_PATH];
+
+ strcpy(event_key, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
+ strcat(event_key, domain);
+ if (!RegCreateKey(HKEY_LOCAL_MACHINE, event_key, &key)) {
+ RegSetValueEx(key, "EventMessageFile", 0, REG_SZ, (LPBYTE)&dll_file_name[0],
+ strlen(dll_file_name) + 1);
+ ts = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+
+ RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, (LPBYTE) &ts, sizeof(DWORD));
+ RegCloseKey(key);
+ }
+ strcpy(log_domain, domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
+{
+ const char *d;
+ TCN_ALLOC_CSTRING(domain);
+
+ UNREFERENCED(o);
+
+ if ((d = J2S(domain)) == NULL)
+ d = LOG_MSG_DOMAIN;
+ init_log_source(d);
+
+ TCN_FREE_CSTRING(domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
+ jstring msg)
+{
+ TCN_ALLOC_CSTRING(msg);
+ DWORD id = LOG_MSG_DEBUG;
+ WORD il = EVENTLOG_SUCCESS;
+ HANDLE source;
+ const char *messages[1];
+ UNREFERENCED(o);
+
+ switch (level) {
+ case TCN_LOG_EMERG:
+ id = LOG_MSG_EMERG;
+ il = EVENTLOG_ERROR_TYPE;
+ break;
+ case TCN_LOG_ERROR:
+ id = LOG_MSG_ERROR;
+ il = EVENTLOG_ERROR_TYPE;
+ break;
+ case TCN_LOG_NOTICE:
+ id = LOG_MSG_NOTICE;
+ il = EVENTLOG_WARNING_TYPE;
+ break;
+ case TCN_LOG_WARN:
+ id = LOG_MSG_WARN;
+ il = EVENTLOG_WARNING_TYPE;
+ break;
+ case TCN_LOG_INFO:
+ id = LOG_MSG_INFO;
+ il = EVENTLOG_INFORMATION_TYPE;
+ break;
+ }
+
+ messages[0] = J2S(msg);
+ source = RegisterEventSource(NULL, log_domain);
+
+ if (source != NULL) {
+ ReportEvent(source, il,
+ 0,
+ id,
+ NULL,
+ 1, 0,
+ messages, NULL);
+ DeregisterEventSource(source);
+ }
+
+ TCN_FREE_CSTRING(msg);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+ UNREFERENCED_STDARGS;
+#ifdef _WIN64
+ if (type == 4)
+ return JNI_TRUE;
+ else
+#endif
+ if (type == 3)
+ return JNI_TRUE;
+ else
+ return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+ jlongArray inf)
+{
+ MEMORYSTATUSEX ms;
+ ULONGLONG st[4];
+ FILETIME ft[4];
+ PROCESS_MEMORY_COUNTERS pmc;
+ jint rv;
+ int i;
+ jsize ilen = (*e)->GetArrayLength(e, inf);
+ jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
+
+ if (ilen < 16) {
+ return APR_EINVAL;
+ }
+ for (i = 0; i < 16; i++)
+ pvals[i] = 0;
+
+ ms.dwLength = sizeof(MEMORYSTATUSEX);
+
+ UNREFERENCED(o);
+ if (GlobalMemoryStatusEx(&ms)) {
+ pvals[0] = (jlong)ms.ullTotalPhys;
+ pvals[1] = (jlong)ms.ullAvailPhys;
+ pvals[2] = (jlong)ms.ullTotalPageFile;
+ pvals[3] = (jlong)ms.ullAvailPageFile;
+ /* Slots 4 and 5 are for shared memory */
+ pvals[6] = (jlong)ms.dwMemoryLoad;
+ }
+ else
+ goto cleanup;
+
+ memset(st, 0, sizeof(st));
+
+ if (fnGetSystemTimes) {
+ if ((*fnGetSystemTimes)(&ft[0], &ft[1], &ft[2])) {
+ st[0] = (((ULONGLONG)ft[0].dwHighDateTime << 32) | ft[0].dwLowDateTime) / 10;
+ st[1] = (((ULONGLONG)ft[1].dwHighDateTime << 32) | ft[1].dwLowDateTime) / 10;
+ st[2] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
+ }
+ else
+ goto cleanup;
+ }
+#if (_WIN32_WINNT < 0x0501)
+ else if (fnNtQuerySystemInformation) {
+ BYTE buf[2048]; /* This should ne enough for 32 processors */
+ NTSTATUS rs = (*fnNtQuerySystemInformation)(SystemProcessorPerformanceInformation,
+ (LPVOID)buf, 2048, NULL);
+ if (rs == 0) {
+ PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pspi = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)&buf[0];
+ DWORD i;
+ /* Calculate all processors */
+ for (i = 0; i < dll_system_info.dwNumberOfProcessors; i++) {
+ st[0] += pspi[i].IdleTime.QuadPart / 10;
+ st[1] += pspi[i].KernelTime.QuadPart / 10;
+ st[2] += pspi[i].UserTime.QuadPart / 10;
+ }
+ }
+ else
+ goto cleanup;
+ }
+#endif
+ pvals[7] = st[0];
+ pvals[8] = st[1];
+ pvals[9] = st[2];
+
+ memset(st, 0, sizeof(st));
+ if (GetProcessTimes(GetCurrentProcess(), &ft[0], &ft[1], &ft[2], &ft[3])) {
+ FileTimeToAprTime((apr_time_t *)&st[0], &ft[0]);
+ st[1] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
+ st[2] = (((ULONGLONG)ft[3].dwHighDateTime << 32) | ft[3].dwLowDateTime) / 10;
+ }
+ pvals[10] = st[0];
+ pvals[11] = st[1];
+ pvals[12] = st[2];
+
+ if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
+ pvals[13] = pmc.WorkingSetSize;
+ pvals[14] = pmc.PeakWorkingSetSize;
+ pvals[15] = pmc.PageFaultCount;
+ }
+
+ (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+ return APR_SUCCESS;
+cleanup:
+ rv = apr_get_os_error();
+ (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+ return rv;
+}
+
+static DWORD WINAPI password_thread(void *data)
+{
+ tcn_pass_cb_t *cb = (tcn_pass_cb_t *)data;
+ MSG msg;
+ HWINSTA hwss;
+ HWINSTA hwsu;
+ HDESK hwds;
+ HDESK hwdu;
+ HWND hwnd;
+
+ /* Ensure connection to service window station and desktop, and
+ * save their handles.
+ */
+ GetDesktopWindow();
+ hwss = GetProcessWindowStation();
+ hwds = GetThreadDesktop(GetCurrentThreadId());
+
+ /* Impersonate the client and connect to the User's
+ * window station and desktop.
+ */
+ hwsu = OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED);
+ if (hwsu == NULL) {
+ ExitThread(1);
+ return 1;
+ }
+ SetProcessWindowStation(hwsu);
+ hwdu = OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED);
+ if (hwdu == NULL) {
+ SetProcessWindowStation(hwss);
+ CloseWindowStation(hwsu);
+ ExitThread(1);
+ return 1;
+ }
+ SetThreadDesktop(hwdu);
+
+ hwnd = CreateDialog(dll_instance, MAKEINTRESOURCE(1001), NULL, NULL);
+ if (hwnd != NULL)
+ ShowWindow(hwnd, SW_SHOW);
+ else {
+ ExitThread(1);
+ return 1;
+ }
+ while (1) {
+ if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
+ if (msg.message == WM_KEYUP) {
+ int nVirtKey = (int)msg.wParam;
+ if (nVirtKey == VK_ESCAPE) {
+ DestroyWindow(hwnd);
+ break;
+ }
+ else if (nVirtKey == VK_RETURN) {
+ HWND he = GetDlgItem(hwnd, 1002);
+ if (he) {
+ int n = GetWindowText(he, cb->password, SSL_MAX_PASSWORD_LEN - 1);
+ cb->password[n] = '\0';
+ }
+ DestroyWindow(hwnd);
+ break;
+ }
+ }
+ TranslateMessage(&msg);
+ DispatchMessage(&msg);
+ }
+ else
+ Sleep(100);
+ }
+ /* Restore window station and desktop.
+ */
+ SetThreadDesktop(hwds);
+ SetProcessWindowStation(hwss);
+ CloseDesktop(hwdu);
+ CloseWindowStation(hwsu);
+
+ ExitThread(0);
+ return 0;
+}
+
+int WIN32_SSL_password_prompt(tcn_pass_cb_t *data)
+{
+ DWORD id;
+ HANDLE thread;
+ /* TODO: See how to display this from service mode */
+ thread = CreateThread(NULL, 0,
+ password_thread, data,
+ 0, &id);
+ WaitForSingleObject(thread, INFINITE);
+ CloseHandle(thread);
+ return (int)strlen(data->password);
+}
+
+
--- /dev/null
+/* Copyright 2000-2006 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/*\r
+ *\r
+ * @author Mladen Turk\r
+ * @version $Revision: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $\r
+ */\r
+\r
+#include "tcn.h"\r
+\r
+TCN_IMPLEMENT_CALL(jlong, Address, info)(TCN_STDARGS,\r
+ jstring hostname,\r
+ jint family, jint port,\r
+ jint flags, jlong pool)\r
+{\r
+ apr_pool_t *p = J2P(pool, apr_pool_t *);\r
+ TCN_ALLOC_CSTRING(hostname);\r
+ apr_sockaddr_t *sa = NULL;\r
+ apr_int32_t f;\r
+\r
+\r
+ UNREFERENCED(o);\r
+ GET_S_FAMILY(f, family);\r
+ TCN_THROW_IF_ERR(apr_sockaddr_info_get(&sa,\r
+ J2S(hostname), f, (apr_port_t)port,\r
+ (apr_int32_t)flags, p), sa);\r
+\r
+cleanup:\r
+ TCN_FREE_CSTRING(hostname);\r
+ return P2J(sa);\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jstring, Address, getnameinfo)(TCN_STDARGS,\r
+ jlong sa, jint flags)\r
+{\r
+ apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);\r
+ char *hostname;\r
+\r
+ UNREFERENCED(o);\r
+ if (apr_getnameinfo(&hostname, s, (apr_int32_t)flags) == APR_SUCCESS)\r
+ return AJP_TO_JSTRING(hostname);\r
+ else\r
+ return NULL;\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jstring, Address, getip)(TCN_STDARGS, jlong sa)\r
+{\r
+ apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);\r
+ char *ipaddr;\r
+\r
+ UNREFERENCED(o);\r
+ if (apr_sockaddr_ip_get(&ipaddr, s) == APR_SUCCESS)\r
+ return AJP_TO_JSTRING(ipaddr);\r
+ else\r
+ return NULL;\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jlong, Address, get)(TCN_STDARGS, jint which,\r
+ jlong sock)\r
+{\r
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+ apr_sockaddr_t *sa = NULL;\r
+\r
+ UNREFERENCED(o);\r
+ TCN_THROW_IF_ERR(apr_socket_addr_get(&sa,\r
+ (apr_interface_e)which, s->sock), sa);\r
+cleanup:\r
+ return P2J(sa);\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jint, Address, equal)(TCN_STDARGS,\r
+ jlong a, jlong b)\r
+{\r
+ apr_sockaddr_t *sa = J2P(a, apr_sockaddr_t *);\r
+ apr_sockaddr_t *sb = J2P(b, apr_sockaddr_t *);\r
+\r
+ UNREFERENCED_STDARGS;\r
+ return apr_sockaddr_equal(sa, sb) ? JNI_TRUE : JNI_FALSE;\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jint, Address, getservbyname)(TCN_STDARGS,\r
+ jlong sa, jstring servname)\r
+{\r
+ apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);\r
+ TCN_ALLOC_CSTRING(servname);\r
+ apr_status_t rv;\r
+\r
+ UNREFERENCED(o);\r
+ rv = apr_getservbyname(s, J2S(servname));\r
+ TCN_FREE_CSTRING(servname);\r
+ return (jint)rv;\r
+}\r
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_file_io.h"
+
+TCN_IMPLEMENT_CALL(jint, Directory, make)(TCN_STDARGS, jstring path,
+ jint perm, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(path);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_dir_make(J2S(path), (apr_fileperms_t)perm, p);
+ TCN_FREE_CSTRING(path);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, makeRecursive)(TCN_STDARGS, jstring path,
+ jint perm, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(path);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_dir_make_recursive(J2S(path), (apr_fileperms_t)perm, p);
+ TCN_FREE_CSTRING(path);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, remove)(TCN_STDARGS, jstring path,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(path);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_dir_remove(J2S(path), p);
+ TCN_FREE_CSTRING(path);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Directory, tempGet)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ jstring name = NULL;
+ const char *tname;
+
+ UNREFERENCED(o);
+ if (apr_temp_dir_get(&tname, p) == APR_SUCCESS)
+ name = AJP_TO_JSTRING(tname);
+
+ return name;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Directory, open)(TCN_STDARGS, jstring path,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_dir_t *d = NULL;
+ TCN_ALLOC_CSTRING(path);
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_dir_open(&d, J2S(path), p), d);
+
+cleanup:
+ TCN_FREE_CSTRING(path);
+ return P2J(d);
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, close)(TCN_STDARGS, jlong dir)
+{
+ apr_dir_t *d = J2P(dir, apr_dir_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_dir_close(d);
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, rewind)(TCN_STDARGS, jlong dir)
+{
+ apr_dir_t *d = J2P(dir, apr_dir_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_dir_rewind(d);
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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"
+
+static const char *tcn_errors[] = {
+ "Unknown user error",
+ /* TCN_TIMEUP */ "Operation timed out",
+ /* TCN_EAGAIN */ "There is no data ready",
+ /* TCN_EINTR */ "Interrupted system call",
+ /* TCN_EINPROGRESS */ "Operation in progress",
+ /* TCN_ETIMEDOUT */ "Connection timed out",
+ NULL
+};
+
+/* Merge IS_ETIMEDOUT with APR_TIMEUP
+ */
+#define TCN_STATUS_IS_ETIMEDOUT(x) (APR_STATUS_IS_ETIMEDOUT((x)) || ((x) == APR_TIMEUP))
+/*
+ * Convenience function to help throw an java.lang.Exception.
+ */
+void tcn_ThrowException(JNIEnv *env, const char *msg)
+{
+ jclass javaExceptionClass;
+
+ javaExceptionClass = (*env)->FindClass(env, "java/lang/Exception");
+ if (javaExceptionClass == NULL) {
+ fprintf(stderr, "Cannot find java/lang/Exception class\n");
+ return;
+ }
+ (*env)->ThrowNew(env, javaExceptionClass, msg);
+ (*env)->DeleteLocalRef(env, javaExceptionClass);
+
+}
+
+void tcn_ThrowMemoryException(JNIEnv *env, const char *file, int line, const char *msg)
+{
+ jclass javaExceptionClass;
+ javaExceptionClass = (*env)->FindClass(env, "java/lang/OutOfMemoryError");
+ if (javaExceptionClass == NULL) {
+ fprintf(stderr, "Cannot find java/lang/OutOfMemoryError\n");
+ return;
+ }
+
+ if (file) {
+ char fmt[TCN_BUFFER_SZ];
+ char *f = (char *)(file + strlen(file) - 1);
+ while (f != file && '\\' != *f && '/' != *f) {
+ f--;
+ }
+ if (f != file) {
+ f++;
+ }
+ sprintf(fmt, "%s for [%s::%04d]", msg, line, f);
+ (*env)->ThrowNew(env, javaExceptionClass, &fmt[0]);
+ }
+ else
+ (*env)->ThrowNew(env, javaExceptionClass, msg);
+ (*env)->DeleteLocalRef(env, javaExceptionClass);
+
+}
+
+
+void tcn_Throw(JNIEnv *env, const char *fmt, ...)
+{
+ char msg[TCN_BUFFER_SZ] = {'\0'};
+ va_list ap;
+
+ va_start(ap, fmt);
+ apr_vsnprintf(msg, TCN_BUFFER_SZ, fmt, ap);
+ tcn_ThrowException(env, msg);
+ va_end(ap);
+}
+
+/*
+ * Convenience function to help throw an APR Exception
+ * from native error code.
+ */
+void tcn_ThrowAPRException(JNIEnv *e, apr_status_t err)
+{
+ jclass aprErrorClass;
+ jmethodID constructorID = 0;
+ jobject throwObj;
+ jstring jdescription;
+ char serr[512] = {0};
+
+ aprErrorClass = (*e)->FindClass(e, TCN_ERROR_CLASS);
+ if (aprErrorClass == NULL) {
+ fprintf(stderr, "Cannot find " TCN_ERROR_CLASS " class\n");
+ return;
+ }
+
+ /* Find the constructor ID */
+ constructorID = (*e)->GetMethodID(e, aprErrorClass,
+ "<init>",
+ "(ILjava/lang/String;)V");
+ if (constructorID == NULL) {
+ fprintf(stderr,
+ "Cannot find constructor for " TCN_ERROR_CLASS " class\n");
+ goto cleanup;
+ }
+
+ apr_strerror(err, serr, 512);
+ /* Obtain the string objects */
+ jdescription = AJP_TO_JSTRING(serr);
+ if (jdescription == NULL) {
+ fprintf(stderr,
+ "Cannot allocate description for " TCN_ERROR_CLASS " class\n");
+ goto cleanup;
+ }
+ /* Create the APR Error object */
+ throwObj = (*e)->NewObject(e, aprErrorClass, constructorID,
+ (jint)err, jdescription);
+ if (throwObj == NULL) {
+ fprintf(stderr,
+ "Cannot allocate new " TCN_ERROR_CLASS " object\n");
+ goto cleanup;
+ }
+
+ (*e)->Throw(e, throwObj);
+cleanup:
+ (*e)->DeleteLocalRef(e, aprErrorClass);
+}
+
+
+TCN_IMPLEMENT_CALL(jint, Error, osError)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ return (jint)apr_get_os_error();
+}
+
+TCN_IMPLEMENT_CALL(jint, Error, netosError)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ return (jint)apr_get_netos_error();
+}
+
+TCN_IMPLEMENT_CALL(jstring, Error, strerror)(TCN_STDARGS, jint err)
+{
+ char serr[512] = {0};
+ jstring jerr;
+
+ UNREFERENCED(o);
+ if (err >= TCN_TIMEUP && err <= TCN_ETIMEDOUT) {
+ err -= TCN_TIMEUP;
+ jerr = AJP_TO_JSTRING(tcn_errors[err + 1]);
+ }
+ else {
+ apr_strerror(err, serr, 512);
+ jerr = AJP_TO_JSTRING(serr);
+ }
+ return jerr;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Status, is)(TCN_STDARGS, jint err, jint idx)
+{
+#define APR_IS(I, E) case I: if (E(err)) return JNI_TRUE; break
+#define APR_ISX(I, E, T) case I: if (E(err) || (err == T)) return JNI_TRUE; break
+
+ UNREFERENCED_STDARGS;
+ switch (idx) {
+ APR_IS(1, APR_STATUS_IS_ENOSTAT);
+ APR_IS(2, APR_STATUS_IS_ENOPOOL);
+ /* empty slot: +3 */
+ APR_IS(4, APR_STATUS_IS_EBADDATE);
+ APR_IS(5, APR_STATUS_IS_EINVALSOCK);
+ APR_IS(6, APR_STATUS_IS_ENOPROC);
+ APR_IS(7, APR_STATUS_IS_ENOTIME);
+ APR_IS(8, APR_STATUS_IS_ENODIR);
+ APR_IS(9, APR_STATUS_IS_ENOLOCK);
+ APR_IS(10, APR_STATUS_IS_ENOPOLL);
+ APR_IS(11, APR_STATUS_IS_ENOSOCKET);
+ APR_IS(12, APR_STATUS_IS_ENOTHREAD);
+ APR_IS(13, APR_STATUS_IS_ENOTHDKEY);
+ APR_IS(14, APR_STATUS_IS_EGENERAL);
+ APR_IS(15, APR_STATUS_IS_ENOSHMAVAIL);
+ APR_IS(16, APR_STATUS_IS_EBADIP);
+ APR_IS(17, APR_STATUS_IS_EBADMASK);
+ /* empty slot: +18 */
+ APR_IS(19, APR_STATUS_IS_EDSOOPEN);
+ APR_IS(20, APR_STATUS_IS_EABSOLUTE);
+ APR_IS(21, APR_STATUS_IS_ERELATIVE);
+ APR_IS(22, APR_STATUS_IS_EINCOMPLETE);
+ APR_IS(23, APR_STATUS_IS_EABOVEROOT);
+ APR_IS(24, APR_STATUS_IS_EBADPATH);
+ APR_IS(25, APR_STATUS_IS_EPATHWILD);
+ APR_IS(26, APR_STATUS_IS_ESYMNOTFOUND);
+ APR_IS(27, APR_STATUS_IS_EPROC_UNKNOWN);
+ APR_IS(28, APR_STATUS_IS_ENOTENOUGHENTROPY);
+
+
+ /* APR_Error */
+ APR_IS(51, APR_STATUS_IS_INCHILD);
+ APR_IS(52, APR_STATUS_IS_INPARENT);
+ APR_IS(53, APR_STATUS_IS_DETACH);
+ APR_IS(54, APR_STATUS_IS_NOTDETACH);
+ APR_IS(55, APR_STATUS_IS_CHILD_DONE);
+ APR_IS(56, APR_STATUS_IS_CHILD_NOTDONE);
+ APR_ISX(57, APR_STATUS_IS_TIMEUP, TCN_TIMEUP);
+ APR_IS(58, APR_STATUS_IS_INCOMPLETE);
+ /* empty slot: +9 */
+ /* empty slot: +10 */
+ /* empty slot: +11 */
+ APR_IS(62, APR_STATUS_IS_BADCH);
+ APR_IS(63, APR_STATUS_IS_BADARG);
+ APR_IS(64, APR_STATUS_IS_EOF);
+ APR_IS(65, APR_STATUS_IS_NOTFOUND);
+ /* empty slot: +16 */
+ /* empty slot: +17 */
+ /* empty slot: +18 */
+ APR_IS(69, APR_STATUS_IS_ANONYMOUS);
+ APR_IS(70, APR_STATUS_IS_FILEBASED);
+ APR_IS(71, APR_STATUS_IS_KEYBASED);
+ APR_IS(72, APR_STATUS_IS_EINIT);
+ APR_IS(73, APR_STATUS_IS_ENOTIMPL);
+ APR_IS(74, APR_STATUS_IS_EMISMATCH);
+ APR_IS(75, APR_STATUS_IS_EBUSY);
+ /* Socket errors */
+ APR_ISX(90, APR_STATUS_IS_EAGAIN, TCN_EAGAIN);
+ APR_ISX(91, TCN_STATUS_IS_ETIMEDOUT, TCN_ETIMEDOUT);
+ APR_IS(92, APR_STATUS_IS_ECONNABORTED);
+ APR_IS(93, APR_STATUS_IS_ECONNRESET);
+ APR_ISX(94, APR_STATUS_IS_EINPROGRESS, TCN_EINPROGRESS);
+ APR_ISX(95, APR_STATUS_IS_EINTR, TCN_EINTR);
+ APR_IS(96, APR_STATUS_IS_ENOTSOCK);
+ APR_IS(97, APR_STATUS_IS_EINVAL);
+ }
+ return JNI_FALSE;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_file_io.h"
+
+
+TCN_IMPLEMENT_CALL(jint, File, close)(TCN_STDARGS, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_close(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, eof)(TCN_STDARGS, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_eof(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, flush)(TCN_STDARGS, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_flush(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, unlock)(TCN_STDARGS, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_unlock(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, flagsGet)(TCN_STDARGS, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_flags_get(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, lock)(TCN_STDARGS, jlong file, jint flags)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_lock(f, (int)flags);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, trunc)(TCN_STDARGS, jlong file, jlong off)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_trunc(f, (apr_off_t)off);
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, open)(TCN_STDARGS, jstring fname,
+ jint flag, jint perm,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_file_t *f = NULL;
+ TCN_ALLOC_CSTRING(fname);
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_file_open(&f, J2S(fname), (apr_int32_t)flag,
+ (apr_fileperms_t)perm, p), f);
+
+cleanup:
+ TCN_FREE_CSTRING(fname);
+ return P2J(f);
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, mktemp)(TCN_STDARGS, jstring templ,
+ jint flags,
+ jint pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_file_t *f = NULL;
+ char *ctempl = tcn_strdup(e, templ);
+
+ UNREFERENCED(o);
+ if (!ctempl) {
+ TCN_THROW_OS_ERROR(e);
+ return 0;
+ }
+ TCN_THROW_IF_ERR(apr_file_mktemp(&f, ctempl,
+ (apr_int32_t)flags, p), f);
+
+cleanup:
+ free(ctempl);
+ return P2J(f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, remove)(TCN_STDARGS, jstring path, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(path);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_file_remove(J2S(path), p);
+ TCN_FREE_CSTRING(path);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, rename)(TCN_STDARGS, jstring from,
+ jstring to, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(from);
+ TCN_ALLOC_CSTRING(to);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_file_rename(J2S(from), J2S(to), p);
+ TCN_FREE_CSTRING(from);
+ TCN_FREE_CSTRING(to);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, copy)(TCN_STDARGS, jstring from,
+ jstring to, jint perms, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(from);
+ TCN_ALLOC_CSTRING(to);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_file_copy(J2S(from), J2S(to), (apr_fileperms_t)perms, p);
+ TCN_FREE_CSTRING(from);
+ TCN_FREE_CSTRING(to);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, append)(TCN_STDARGS, jstring from,
+ jstring to, jint perms, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(from);
+ TCN_ALLOC_CSTRING(to);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_file_append(J2S(from), J2S(to), (apr_fileperms_t)perms, p);
+ TCN_FREE_CSTRING(from);
+ TCN_FREE_CSTRING(to);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jstring, File, nameGet)(TCN_STDARGS, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ jstring name = NULL;
+ const char *fname;
+
+ UNREFERENCED(o);
+ if (apr_file_name_get(&fname, f) == APR_SUCCESS)
+ name = AJP_TO_JSTRING(fname);
+
+ return name;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, permsSet)(TCN_STDARGS, jstring file, jint perms)
+{
+ TCN_ALLOC_CSTRING(file);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_file_perms_set(J2S(file), (apr_fileperms_t)perms);
+ TCN_FREE_CSTRING(file);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, attrsSet)(TCN_STDARGS, jstring file, jint attrs,
+ jint mask, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(file);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_file_attrs_set(J2S(file), (apr_fileattrs_t)attrs,
+ (apr_fileattrs_t)mask, p);
+ TCN_FREE_CSTRING(file);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, mtimeSet)(TCN_STDARGS, jstring file, jlong mtime,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(file);
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ rv = apr_file_mtime_set(J2S(file), J2T(mtime), p);
+ TCN_FREE_CSTRING(file);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, seek)(TCN_STDARGS, jlong file,
+ jint where, jlong offset)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_off_t pos = (apr_off_t)offset;
+ apr_seek_where_t w;
+ UNREFERENCED(o);
+ switch (where) {
+ case 1:
+ w = APR_CUR;
+ break;
+ case 2:
+ w = APR_END;
+ break;
+ default:
+ w = APR_SET;
+ break;
+ }
+ TCN_THROW_IF_ERR(apr_file_seek(f, w, &pos), pos);
+
+cleanup:
+ return (jlong)pos;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, putc)(TCN_STDARGS, jbyte c, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_putc((char)c, f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, getc)(TCN_STDARGS, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ char ch;
+
+ UNREFERENCED_STDARGS;
+ TCN_THROW_IF_ERR(apr_file_getc(&ch, f), ch);
+
+cleanup:
+ return (jint)ch;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, ungetc)(TCN_STDARGS, jbyte c, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_ungetc((char)c, f);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, puts)(TCN_STDARGS, jbyteArray str, jlong file)
+{
+ apr_status_t rv = APR_EINVAL;
+ apr_file_t *f = J2P(file, apr_file_t *);
+ jbyte *bytes = (*e)->GetPrimitiveArrayCritical(e, str, NULL);
+
+ UNREFERENCED(o);
+ if (bytes) {
+ rv = apr_file_puts((const char *)bytes, f);
+ (*e)->ReleasePrimitiveArrayCritical(e, str, bytes, JNI_ABORT);
+ }
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, write)(TCN_STDARGS, jlong file,
+ jbyteArray buf, jint offset, jint towrite)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)towrite;
+ jbyte *bytes = (*e)->GetPrimitiveArrayCritical(e, buf, NULL);
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ if (towrite < 0)
+ towrite = (*e)->GetArrayLength(e, buf);
+ ss = apr_file_write(f, bytes + offset, &nbytes);
+
+ (*e)->ReleasePrimitiveArrayCritical(e, buf, bytes, JNI_ABORT);
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writeb)(TCN_STDARGS, jlong file,
+ jobject buf, jint offset, jint towrite)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)towrite;
+ char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+ apr_status_t ss = APR_EINVAL;
+
+ UNREFERENCED(o);
+ if (bytes)
+ ss = apr_file_write(f, bytes + offset, &nbytes);
+
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writeFull)(TCN_STDARGS, jlong file,
+ jbyteArray buf, jint offset, jint towrite)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)towrite;
+ apr_size_t written = 0;
+ apr_status_t ss;
+ jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+
+ UNREFERENCED(o);
+ if (towrite < 0)
+ towrite = (*e)->GetArrayLength(e, buf);
+ ss = apr_file_write_full(f, bytes + offset, nbytes, &written);
+
+ (*e)->ReleaseByteArrayElements(e, buf, bytes, JNI_ABORT);
+ if (ss == APR_SUCCESS)
+ return (jint)written;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writeFullb)(TCN_STDARGS, jlong file,
+ jobject buf, jint offset, jint towrite)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)towrite;
+ apr_size_t written = 0;
+ apr_status_t ss = APR_EINVAL;
+ char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+
+ UNREFERENCED(o);
+ if (bytes)
+ ss = apr_file_write_full(f, bytes + offset, nbytes, &written);
+
+ if (ss == APR_SUCCESS)
+ return (jint)written;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writev)(TCN_STDARGS, jlong file,
+ jobjectArray bufs)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ jsize nvec = (*e)->GetArrayLength(e, bufs);
+ jsize i;
+ struct iovec vec[APR_MAX_IOVEC_SIZE];
+ jobject ba[APR_MAX_IOVEC_SIZE];
+ apr_size_t written = 0;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+
+ if (nvec >= APR_MAX_IOVEC_SIZE) {
+ /* TODO: Throw something here */
+ return 0;
+ }
+ for (i = 0; i < nvec; i++) {
+ ba[i] = (*e)->GetObjectArrayElement(e, bufs, i);
+ vec[i].iov_len = (*e)->GetArrayLength(e, ba[i]);
+ vec[i].iov_base = (*e)->GetByteArrayElements(e, ba[i], NULL);
+ }
+
+ ss = apr_file_writev(f, vec, nvec, &written);
+
+ for (i = 0; i < nvec; i++) {
+ (*e)->ReleaseByteArrayElements(e, ba[i], vec[i].iov_base, JNI_ABORT);
+ }
+ if (ss == APR_SUCCESS)
+ return (jint)written;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, writevFull)(TCN_STDARGS, jlong file,
+ jobjectArray bufs)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ jsize nvec = (*e)->GetArrayLength(e, bufs);
+ jsize i;
+ struct iovec vec[APR_MAX_IOVEC_SIZE];
+ jobject ba[APR_MAX_IOVEC_SIZE];
+ apr_size_t written = 0;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+
+ if (nvec >= APR_MAX_IOVEC_SIZE) {
+ /* TODO: Throw something here */
+ return 0;
+ }
+ for (i = 0; i < nvec; i++) {
+ ba[i] = (*e)->GetObjectArrayElement(e, bufs, i);
+ vec[i].iov_len = (*e)->GetArrayLength(e, ba[i]);
+ vec[i].iov_base = (*e)->GetByteArrayElements(e, ba[i], NULL);
+ }
+#if (APR_VERSION_MAJOR >= 1) && (APR_VERSION_MINOR >= 1)
+ ss = apr_file_writev_full(f, vec, nvec, &written);
+#else
+ ss = apr_file_writev(f, vec, nvec, &written);
+#endif
+
+ for (i = 0; i < nvec; i++) {
+ (*e)->ReleaseByteArrayElements(e, ba[i], vec[i].iov_base,
+ JNI_ABORT);
+ }
+ if (ss == APR_SUCCESS)
+ return (jint)written;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, read)(TCN_STDARGS, jlong file,
+ jbyteArray buf, jint offset,
+ jint toread)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)toread;
+ jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ ss = apr_file_read(f, bytes + offset, &nbytes);
+
+ (*e)->ReleaseByteArrayElements(e, buf, bytes,
+ ss == APR_SUCCESS ? 0 : JNI_ABORT);
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, readb)(TCN_STDARGS, jlong file,
+ jobject buf, jint offset,
+ jint toread)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)toread;
+ char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+ apr_status_t ss = APR_EINVAL;
+
+ UNREFERENCED(o);
+ if (bytes)
+ ss = apr_file_read(f, bytes + offset, &nbytes);
+
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, readFull)(TCN_STDARGS, jlong file,
+ jbyteArray buf, jint offset,
+ jint toread)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)toread;
+ apr_size_t nread = 0;
+ apr_status_t ss;
+ jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+
+ UNREFERENCED(o);
+ ss = apr_file_read_full(f, bytes + offset, nbytes, &nread);
+
+ (*e)->ReleaseByteArrayElements(e, buf, bytes,
+ ss == APR_SUCCESS ? 0 : JNI_ABORT);
+ if (ss == APR_SUCCESS)
+ return (jint)nread;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, readFullb)(TCN_STDARGS, jlong file,
+ jobject buf, jint offset,
+ jint toread)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_size_t nbytes = (apr_size_t)toread;
+ apr_size_t nread = 0;
+ char *bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+ apr_status_t ss = APR_EINVAL;
+
+ UNREFERENCED(o);
+ if (bytes)
+ ss = apr_file_read_full(f, bytes + offset, nbytes, &nread);
+
+ if (ss == APR_SUCCESS)
+ return (jint)nread;
+ else
+ return -(jint)ss;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, gets)(TCN_STDARGS, jbyteArray buf, jint offset,
+ jlong file)
+{
+ apr_status_t rv;
+ apr_file_t *f = J2P(file, apr_file_t *);
+ jsize nbytes = (*e)->GetArrayLength(e, buf);
+ jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+
+ UNREFERENCED(o);
+ rv = apr_file_gets((char*)(bytes + offset),nbytes - offset, f);
+ (*e)->ReleaseByteArrayElements(e, buf, bytes,
+ rv == APR_SUCCESS ? 0 : JNI_ABORT);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, pipeCreate)(TCN_STDARGS, jlongArray io, jlong pool)
+{
+ apr_status_t rv;
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ jsize npipes = (*e)->GetArrayLength(e, io);
+ jlong *pipes = (*e)->GetLongArrayElements(e, io, NULL);
+ apr_file_t *in;
+ apr_file_t *out;
+
+ UNREFERENCED(o);
+ if (npipes < 2) {
+ (*e)->ReleaseLongArrayElements(e, io, pipes, JNI_ABORT);
+ return APR_EINVAL;
+ }
+
+ rv = apr_file_pipe_create(&in, &out, p);
+ if (rv == APR_SUCCESS) {
+ pipes[0] = P2J(in);
+ pipes[1] = P2J(out);
+ (*e)->ReleaseLongArrayElements(e, io, pipes, 0);
+ }
+ else
+ (*e)->ReleaseLongArrayElements(e, io, pipes, JNI_ABORT);
+
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, pipeTimeoutSet)(TCN_STDARGS, jlong pipe,
+ jlong timeout)
+{
+ apr_file_t *f = J2P(pipe, apr_file_t *);
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_pipe_timeout_set(f, J2T(timeout));
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, pipeTimeoutGet)(TCN_STDARGS, jlong pipe)
+{
+ apr_file_t *f = J2P(pipe, apr_file_t *);
+ apr_interval_time_t timeout;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_file_pipe_timeout_get(f, &timeout), timeout);
+
+cleanup:
+ return (jlong)timeout;
+}
+
+TCN_IMPLEMENT_CALL(jlong, File, dup)(TCN_STDARGS, jlong newf, jlong file,
+ jlong pool)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_file_t *d = J2P(newf, apr_file_t *);
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_file_dup(&d, f, p), d);
+
+cleanup:
+ return P2J(d);
+}
+
+TCN_IMPLEMENT_CALL(jint, File, dup2)(TCN_STDARGS, jlong newf, jlong file,
+ jlong pool)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_file_t *d = J2P(newf, apr_file_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_file_dup2(d, f, p);
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_file_io.h"
+
+#define DECLARE_FINFO_FIELD(name) static jfieldID _fid##name = NULL
+#define FINFO_FIELD(name) _fid##name
+
+#define GET_FINFO_I(N) \
+ _fid##N = (*e)->GetFieldID(e, finfo, #N, "I"); \
+ if (_fid##N == NULL) { \
+ (*e)->ExceptionClear(e); \
+ goto cleanup; \
+ } else (void)(0)
+
+#define GET_FINFO_J(N) \
+ _fid##N = (*e)->GetFieldID(e, finfo, #N, "J"); \
+ if (_fid##N == NULL) { \
+ (*e)->ExceptionClear(e); \
+ goto cleanup; \
+ } else (void)(0)
+
+#define GET_FINFO_S(N) \
+ _fid##N = (*e)->GetFieldID(e, finfo, #N, \
+ "Ljava/lang/String;"); \
+ if (_fid##N == NULL) { \
+ (*e)->ExceptionClear(e); \
+ goto cleanup; \
+ } else (void)(0)
+
+#define SET_FINFO_I(N, V) \
+ (*e)->SetIntField(e, obj, _fid##N, (jint)(V))
+
+#define SET_FINFO_J(N, V) \
+ (*e)->SetLongField(e, obj, _fid##N, (jlong)(V))
+
+#define SET_FINFO_S(N, V) \
+ (*e)->SetObjectField(e, obj, _fid##N, \
+ (V) ? AJP_TO_JSTRING((V)) : NULL)
+
+
+#define DECLARE_AINFO_FIELD(name) static jfieldID _aid##name = NULL
+#define AINFO_FIELD(name) _aid##name
+
+#define GET_AINFO_I(N) \
+ _aid##N = (*e)->GetFieldID(e, ainfo, #N, "I"); \
+ if (_aid##N == NULL) { \
+ (*e)->ExceptionClear(e); \
+ goto cleanup; \
+ } else (void)(0)
+
+#define GET_AINFO_J(N) \
+ _aid##N = (*e)->GetFieldID(e, ainfo, #N, "J"); \
+ if (_aid##N == NULL) { \
+ (*e)->ExceptionClear(e); \
+ goto cleanup; \
+ } else (void)(0)
+
+#define GET_AINFO_S(N) \
+ _aid##N = (*e)->GetFieldID(e, ainfo, #N, \
+ "Ljava/lang/String;"); \
+ if (_aid##N == NULL) { \
+ (*e)->ExceptionClear(e); \
+ goto cleanup; \
+ } else (void)(0)
+
+#define SET_AINFO_I(N, V) \
+ (*e)->SetIntField(e, obj, _aid##N, (jint)(V))
+
+#define SET_AINFO_J(N, V) \
+ (*e)->SetLongField(e, obj, _aid##N, (jlong)(V))
+
+#define SET_AINFO_S(N, V) \
+ (*e)->SetObjectField(e, obj, _aid##N, \
+ (V) ? AJP_TO_JSTRING((V)) : NULL)
+
+
+DECLARE_FINFO_FIELD(pool);
+DECLARE_FINFO_FIELD(valid);
+DECLARE_FINFO_FIELD(protection);
+DECLARE_FINFO_FIELD(filetype);
+DECLARE_FINFO_FIELD(user);
+DECLARE_FINFO_FIELD(group);
+DECLARE_FINFO_FIELD(inode);
+DECLARE_FINFO_FIELD(device);
+DECLARE_FINFO_FIELD(nlink);
+DECLARE_FINFO_FIELD(size);
+DECLARE_FINFO_FIELD(csize);
+DECLARE_FINFO_FIELD(atime);
+DECLARE_FINFO_FIELD(mtime);
+DECLARE_FINFO_FIELD(ctime);
+DECLARE_FINFO_FIELD(fname);
+DECLARE_FINFO_FIELD(name);
+DECLARE_FINFO_FIELD(filehand);
+
+DECLARE_AINFO_FIELD(pool);
+DECLARE_AINFO_FIELD(hostname);
+DECLARE_AINFO_FIELD(servname);
+DECLARE_AINFO_FIELD(port);
+DECLARE_AINFO_FIELD(family);
+DECLARE_AINFO_FIELD(next);
+
+static int finfo_class_initialized = 0;
+static int ainfo_class_initialized = 0;
+static jmethodID finfo_class_init = NULL;
+static jmethodID ainfo_class_init = NULL;
+static jclass finfo_class = NULL;
+static jclass ainfo_class = NULL;
+
+apr_status_t tcn_load_finfo_class(JNIEnv *e, jclass finfo)
+{
+ GET_FINFO_J(pool);
+ GET_FINFO_I(valid);
+ GET_FINFO_I(protection);
+ GET_FINFO_I(filetype);
+ GET_FINFO_I(user);
+ GET_FINFO_I(group);
+ GET_FINFO_I(inode);
+ GET_FINFO_I(device);
+ GET_FINFO_I(nlink);
+ GET_FINFO_J(size);
+ GET_FINFO_J(csize);
+ GET_FINFO_J(atime);
+ GET_FINFO_J(mtime);
+ GET_FINFO_J(ctime);
+ GET_FINFO_S(fname);
+ GET_FINFO_S(name);
+ GET_FINFO_J(filehand);
+
+ finfo_class_init = (*e)->GetMethodID(e, finfo,
+ "<init>", "()V");
+ if (finfo_class_init == NULL)
+ goto cleanup;
+ finfo_class_initialized = 1;
+ finfo_class = finfo;
+cleanup:
+ return APR_SUCCESS;
+}
+
+apr_status_t tcn_load_ainfo_class(JNIEnv *e, jclass ainfo)
+{
+ GET_AINFO_J(pool);
+ GET_AINFO_S(hostname);
+ GET_AINFO_S(servname);
+ GET_AINFO_I(port);
+ GET_AINFO_I(family);
+ GET_AINFO_J(next);
+ ainfo_class_init = (*e)->GetMethodID(e, ainfo,
+ "<init>", "()V");
+
+ if (ainfo_class_init == NULL)
+ goto cleanup;
+ ainfo_class_initialized = 1;
+ ainfo_class = ainfo;
+cleanup:
+ return APR_SUCCESS;
+}
+
+static void fill_finfo(JNIEnv *e, jobject obj, apr_finfo_t *info)
+{
+
+ SET_FINFO_J(pool, P2J(info->pool));
+ SET_FINFO_I(valid, info->valid);
+ SET_FINFO_I(protection, info->protection);
+ SET_FINFO_I(filetype, info->filetype);
+ SET_FINFO_I(user, ((jlong)info->user));
+ SET_FINFO_I(group, ((jlong)info->group));
+ SET_FINFO_I(inode, info->inode);
+ SET_FINFO_I(device, info->device);
+ SET_FINFO_I(nlink, info->nlink);
+ SET_FINFO_J(size, info->size);
+ SET_FINFO_J(csize, info->csize);
+ SET_FINFO_J(atime, info->atime);
+ SET_FINFO_J(mtime, info->mtime);
+ SET_FINFO_J(ctime, info->ctime);
+ SET_FINFO_S(fname, info->fname);
+ SET_FINFO_S(name, info->name);
+ SET_FINFO_J(filehand, P2J(info->filehand));
+}
+
+static void fill_ainfo(JNIEnv *e, jobject obj, apr_sockaddr_t *info)
+{
+
+ SET_AINFO_J(pool, P2J(info->pool));
+ SET_AINFO_S(hostname, info->hostname);
+ SET_AINFO_S(servname, info->servname);
+ SET_AINFO_I(port, info->port);
+ SET_AINFO_I(family, info->family);
+ SET_AINFO_J(next, P2J(info->next));
+
+}
+
+TCN_IMPLEMENT_CALL(jint, File, stat)(TCN_STDARGS, jobject finfo,
+ jstring fname, jint wanted,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(fname);
+ apr_status_t rv;
+ apr_finfo_t info;
+
+ UNREFERENCED(o);
+
+ if ((rv = apr_stat(&info, J2S(fname), wanted, p)) == APR_SUCCESS) {
+ jobject io = (*e)->NewLocalRef(e, finfo);
+ fill_finfo(e, io, &info);
+ (*e)->DeleteLocalRef(e, io);
+ }
+ TCN_FREE_CSTRING(fname);
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, File, getStat)(TCN_STDARGS, jstring fname,
+ jint wanted, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(fname);
+ apr_status_t rv;
+ apr_finfo_t info;
+ jobject finfo = NULL;
+
+ UNREFERENCED(o);
+
+ if ((rv = apr_stat(&info, J2S(fname), wanted, p)) == APR_SUCCESS) {
+ finfo = (*e)->NewObject(e, finfo_class, finfo_class_init);
+ if (finfo == NULL)
+ goto cleanup;
+ fill_finfo(e, finfo, &info);
+ }
+ else
+ tcn_ThrowAPRException(e, rv);
+cleanup:
+ TCN_FREE_CSTRING(fname);
+ return finfo;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, infoGet)(TCN_STDARGS, jobject finfo,
+ jint wanted, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_status_t rv;
+ apr_finfo_t info;
+
+ UNREFERENCED(o);
+
+ if ((rv = apr_file_info_get(&info, wanted, f)) == APR_SUCCESS) {
+ jobject io = (*e)->NewLocalRef(e, finfo);
+ fill_finfo(e, io, &info);
+ (*e)->DeleteLocalRef(e, io);
+ }
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, File, getInfo)(TCN_STDARGS, jint wanted, jlong file)
+{
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_status_t rv;
+ apr_finfo_t info;
+
+ UNREFERENCED(o);
+
+ if ((rv = apr_file_info_get(&info, wanted, f)) == APR_SUCCESS) {
+ jobject finfo;
+ finfo = (*e)->NewObject(e, finfo_class, finfo_class_init);
+ if (finfo == NULL)
+ return NULL;
+ fill_finfo(e, finfo, &info);
+ return finfo;
+ }
+ else
+ tcn_ThrowAPRException(e, rv);
+ return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, read)(TCN_STDARGS, jobject finfo,
+ jint wanted, jlong dir)
+{
+ apr_dir_t *d = J2P(dir, apr_dir_t *);
+ apr_status_t rv;
+ apr_finfo_t info;
+
+ UNREFERENCED(o);
+
+ if ((rv = apr_dir_read(&info, wanted, d)) == APR_SUCCESS) {
+ jobject io = (*e)->NewLocalRef(e, finfo);
+ fill_finfo(e, io, &info);
+ if ((*e)->ExceptionCheck(e)) {
+ (*e)->ExceptionClear(e);
+ }
+ else
+ rv = APR_EGENERAL;
+ (*e)->DeleteLocalRef(e, io);
+ }
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Address, fill)(TCN_STDARGS,
+ jobject addr, jlong info)
+{
+ apr_sockaddr_t *i = J2P(info, apr_sockaddr_t *);
+ jobject ao;
+ jboolean rv = JNI_FALSE;
+
+ UNREFERENCED(o);
+
+ if (i) {
+ ao = (*e)->NewLocalRef(e, addr);
+ fill_ainfo(e, ao, i);
+ if ((*e)->ExceptionCheck(e)) {
+ (*e)->ExceptionClear(e);
+ }
+ else
+ rv = JNI_TRUE;
+ (*e)->DeleteLocalRef(e, ao);
+ }
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Address, getInfo)(TCN_STDARGS, jlong info)
+{
+ apr_sockaddr_t *i = J2P(info, apr_sockaddr_t *);
+ jobject sockaddrObj = NULL;
+
+ UNREFERENCED(o);
+
+ /* Create the APR Error object */
+ sockaddrObj = (*e)->NewObject(e, ainfo_class, ainfo_class_init);
+ if (sockaddrObj == NULL)
+ return NULL;
+ fill_ainfo(e, sockaddrObj, i);
+ return sockaddrObj;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_version.h"
+#include "apr_file_io.h"
+#include "apr_mmap.h"
+#include "apr_atomic.h"
+
+#include "tcn_version.h"
+
+#ifdef TCN_DO_STATISTICS
+extern void sp_poll_dump_statistics();
+extern void sp_network_dump_statistics();
+extern void ssl_network_dump_statistics();
+#endif
+
+apr_pool_t *tcn_global_pool = NULL;
+static JavaVM *tcn_global_vm = NULL;
+
+static jclass jString_class;
+static jclass jFinfo_class;
+static jclass jAinfo_class;
+static jmethodID jString_init;
+static jmethodID jString_getBytes;
+
+int tcn_parent_pid = 0;
+
+/* Called by the JVM when APR_JAVA is loaded */
+JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *vm, void *reserved)
+{
+ JNIEnv *env;
+
+ UNREFERENCED(reserved);
+ if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_4)) {
+ return JNI_ERR;
+ }
+ tcn_global_vm = vm;
+
+ /* Initialize global java.lang.String class */
+ TCN_LOAD_CLASS(env, jString_class, "java/lang/String", JNI_ERR);
+ TCN_LOAD_CLASS(env, jFinfo_class, TCN_FINFO_CLASS, JNI_ERR);
+ TCN_LOAD_CLASS(env, jAinfo_class, TCN_AINFO_CLASS, JNI_ERR);
+
+ TCN_GET_METHOD(env, jString_class, jString_init,
+ "<init>", "([B)V", JNI_ERR);
+ TCN_GET_METHOD(env, jString_class, jString_getBytes,
+ "getBytes", "()[B", JNI_ERR);
+
+ if(tcn_load_finfo_class(env, jFinfo_class) != APR_SUCCESS)
+ return JNI_ERR;
+ if(tcn_load_ainfo_class(env, jAinfo_class) != APR_SUCCESS)
+ return JNI_ERR;
+#ifdef WIN32
+ {
+ char *ppid = getenv(TCN_PARENT_IDE);
+ if (ppid)
+ tcn_parent_pid = atoi(ppid);
+ }
+#else
+ tcn_parent_pid = getppid();
+#endif
+ apr_initialize();
+
+ return JNI_VERSION_1_4;
+}
+
+
+/* Called by the JVM before the APR_JAVA is unloaded */
+JNIEXPORT void JNICALL JNI_OnUnload(JavaVM *vm, void *reserved)
+{
+ JNIEnv *env;
+
+ UNREFERENCED(reserved);
+
+ if ((*vm)->GetEnv(vm, (void **)&env, JNI_VERSION_1_2)) {
+ return;
+ }
+ TCN_UNLOAD_CLASS(env, jString_class);
+ TCN_UNLOAD_CLASS(env, jFinfo_class);
+ TCN_UNLOAD_CLASS(env, jAinfo_class);
+ apr_terminate();
+}
+
+jstring tcn_new_stringn(JNIEnv *env, const char *str, size_t l)
+{
+ jstring result;
+ jbyteArray bytes = 0;
+ size_t len = l;
+
+ if (!str)
+ return NULL;
+ if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
+ return NULL; /* out of memory error */
+ }
+ if (l < 0)
+ len = strlen(str);
+ bytes = (*env)->NewByteArray(env, (jsize)len);
+ if (bytes != NULL) {
+ (*env)->SetByteArrayRegion(env, bytes, 0, (jint)len, (jbyte *)str);
+ result = (*env)->NewObject(env, jString_class, jString_init, bytes);
+ (*env)->DeleteLocalRef(env, bytes);
+ return result;
+ } /* else fall through */
+ return NULL;
+}
+
+jbyteArray tcn_new_arrayb(JNIEnv *env, const unsigned char *data, size_t len)
+{
+ jbyteArray bytes = (*env)->NewByteArray(env, (jsize)len);
+ if (bytes != NULL) {
+ (*env)->SetByteArrayRegion(env, bytes, 0, (jint)len, (jbyte *)data);
+ }
+ return bytes;
+}
+
+jobjectArray tcn_new_arrays(JNIEnv *env, size_t len)
+{
+ return (*env)->NewObjectArray(env, (jsize)len, jString_class, NULL);
+}
+
+jstring tcn_new_string(JNIEnv *env, const char *str)
+{
+ if (!str)
+ return NULL;
+ else
+ return (*env)->NewStringUTF(env, str);
+}
+
+char *tcn_get_string(JNIEnv *env, jstring jstr)
+{
+ jbyteArray bytes = NULL;
+ jthrowable exc;
+ char *result = NULL;
+
+ if ((*env)->EnsureLocalCapacity(env, 2) < 0) {
+ return NULL; /* out of memory error */
+ }
+ bytes = (*env)->CallObjectMethod(env, jstr, jString_getBytes);
+ exc = (*env)->ExceptionOccurred(env);
+ if (!exc) {
+ jint len = (*env)->GetArrayLength(env, bytes);
+ result = (char *)malloc(len + 1);
+ if (result == NULL) {
+ TCN_THROW_OS_ERROR(env);
+ (*env)->DeleteLocalRef(env, bytes);
+ return 0;
+ }
+ (*env)->GetByteArrayRegion(env, bytes, 0, len, (jbyte *)result);
+ result[len] = '\0'; /* NULL-terminate */
+ }
+ else {
+ (*env)->DeleteLocalRef(env, exc);
+ }
+ (*env)->DeleteLocalRef(env, bytes);
+
+ return result;
+}
+
+char *tcn_strdup(JNIEnv *env, jstring jstr)
+{
+ char *result = NULL;
+ const char *cjstr;
+
+ cjstr = (const char *)((*env)->GetStringUTFChars(env, jstr, 0));
+ if (cjstr) {
+ result = strdup(cjstr);
+ (*env)->ReleaseStringUTFChars(env, jstr, cjstr);
+ }
+ return result;
+}
+
+char *tcn_pstrdup(JNIEnv *env, jstring jstr, apr_pool_t *pool)
+{
+ char *result = NULL;
+ const char *cjstr;
+
+ cjstr = (const char *)((*env)->GetStringUTFChars(env, jstr, 0));
+ if (cjstr) {
+ result = apr_pstrdup(pool, cjstr);
+ (*env)->ReleaseStringUTFChars(env, jstr, cjstr);
+ }
+ return result;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Library, initialize)(TCN_STDARGS)
+{
+
+ UNREFERENCED_STDARGS;
+ if (!tcn_global_pool) {
+ if (apr_pool_create(&tcn_global_pool, NULL) != APR_SUCCESS) {
+ return JNI_FALSE;
+ }
+ apr_atomic_init(tcn_global_pool);
+ }
+ return JNI_TRUE;
+}
+
+TCN_IMPLEMENT_CALL(void, Library, terminate)(TCN_STDARGS)
+{
+
+ UNREFERENCED_STDARGS;
+ if (tcn_global_pool) {
+#ifdef TCN_DO_STATISTICS
+ fprintf(stderr, "APR Statistical data ....\n");
+#endif
+ apr_pool_destroy(tcn_global_pool);
+ tcn_global_pool = NULL;
+#ifdef TCN_DO_STATISTICS
+ sp_poll_dump_statistics();
+ sp_network_dump_statistics();
+ ssl_network_dump_statistics();
+ fprintf(stderr, "APR Terminated\n");
+#endif
+ }
+}
+
+TCN_IMPLEMENT_CALL(jlong, Library, globalPool)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ return P2J(tcn_global_pool);
+}
+
+TCN_IMPLEMENT_CALL(jint, Library, version)(TCN_STDARGS, jint what)
+{
+ apr_version_t apv;
+
+ UNREFERENCED_STDARGS;
+ apr_version(&apv);
+
+ switch (what) {
+ case 0x01:
+ return TCN_MAJOR_VERSION;
+ break;
+ case 0x02:
+ return TCN_MINOR_VERSION;
+ break;
+ case 0x03:
+ return TCN_PATCH_VERSION;
+ break;
+ case 0x04:
+#ifdef TCN_IS_DEV_VERSION
+ return 1;
+#else
+ return 0;
+#endif
+ break;
+ case 0x11:
+ return apv.major;
+ break;
+ case 0x12:
+ return apv.minor;
+ break;
+ case 0x13:
+ return apv.patch;
+ break;
+ case 0x14:
+ return apv.is_dev;
+ break;
+ }
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Library, versionString)(TCN_STDARGS)
+{
+ UNREFERENCED(o);
+ return AJP_TO_JSTRING(TCN_VERSION_STRING);
+}
+
+TCN_IMPLEMENT_CALL(jstring, Library, aprVersionString)(TCN_STDARGS)
+{
+ UNREFERENCED(o);
+ return AJP_TO_JSTRING(apr_version_string());
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Library, has)(TCN_STDARGS, jint what)
+{
+ jboolean rv = JNI_FALSE;
+ UNREFERENCED_STDARGS;
+ switch (what) {
+ case 0:
+#if APR_HAVE_IPV6
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 1:
+#if APR_HAS_SHARED_MEMORY
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 2:
+#if APR_HAS_THREADS
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 3:
+#if APR_HAS_SENDFILE
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 4:
+#if APR_HAS_MMAP
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 5:
+#if APR_HAS_FORK
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 6:
+#if APR_HAS_RANDOM
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 7:
+#if APR_HAS_OTHER_CHILD
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 8:
+#if APR_HAS_DSO
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 9:
+#if APR_HAS_SO_ACCEPTFILTER
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 10:
+#if APR_HAS_UNICODE_FS
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 11:
+#if APR_HAS_PROC_INVOKED
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 12:
+#if APR_HAS_USER
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 13:
+#if APR_HAS_LARGE_FILES
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 14:
+#if APR_HAS_XTHREAD_FILES
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 15:
+#if APR_HAS_OS_UUID
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 16:
+#if APR_IS_BIGENDIAN
+ rv = JNI_TRUE;
+#endif
+ break;
+
+ case 17:
+#if APR_FILES_AS_SOCKETS
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 18:
+#if APR_CHARSET_EBCDIC
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 19:
+#if APR_TCP_NODELAY_INHERITED
+ rv = JNI_TRUE;
+#endif
+ break;
+ case 20:
+#if APR_O_NONBLOCK_INHERITED
+ rv = JNI_TRUE;
+#endif
+ break;
+ }
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Library, size)(TCN_STDARGS, jint what)
+{
+
+ UNREFERENCED_STDARGS;
+
+ switch (what) {
+ case 1:
+ return APR_SIZEOF_VOIDP;
+ break;
+ case 2:
+ return APR_PATH_MAX;
+ break;
+ case 3:
+ return APRMAXHOSTLEN;
+ break;
+ case 4:
+ return APR_MAX_IOVEC_SIZE;
+ break;
+ case 5:
+ return APR_MAX_SECS_TO_LINGER;
+ break;
+ case 6:
+ return APR_MMAP_THRESHOLD;
+ break;
+ case 7:
+ return APR_MMAP_LIMIT;
+ break;
+
+ }
+ return 0;
+}
+
+TCN_DECLARE(apr_pool_t *) tcn_get_global_pool()
+{
+ if (!tcn_global_pool) {
+ if (apr_pool_create(&tcn_global_pool, NULL) != APR_SUCCESS) {
+ return NULL;
+ }
+ apr_atomic_init(tcn_global_pool);
+ }
+ return tcn_global_pool;
+}
+
+TCN_DECLARE(jclass) tcn_get_string_class()
+{
+ return jString_class;
+}
+
+TCN_DECLARE(JavaVM *) tcn_get_java_vm()
+{
+ return tcn_global_vm;
+}
+
+TCN_DECLARE(jint) tcn_get_java_env(JNIEnv **env)
+{
+ if ((*tcn_global_vm)->GetEnv(tcn_global_vm, (void **)env,
+ JNI_VERSION_1_4)) {
+ return JNI_ERR;
+ }
+ return JNI_OK;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_proc_mutex.h"
+#include "apr_global_mutex.h"
+
+TCN_IMPLEMENT_CALL(jlong, Lock, create)(TCN_STDARGS,
+ jstring fname,
+ jint mech, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_proc_mutex_t *mutex;
+ TCN_ALLOC_CSTRING(fname);
+
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_proc_mutex_create(&mutex, J2S(fname),
+ (apr_lockmech_e)mech, p), mutex);
+
+cleanup:
+ TCN_FREE_CSTRING(fname);
+ return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Lock, childInit)(TCN_STDARGS,
+ jstring fname,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_proc_mutex_t *mutex;
+ TCN_ALLOC_CSTRING(fname);
+
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_proc_mutex_child_init(&mutex,
+ J2S(fname), p), mutex);
+
+cleanup:
+ TCN_FREE_CSTRING(fname);
+ return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, lock)(TCN_STDARGS, jlong mutex)
+{
+ apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_proc_mutex_lock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, trylock)(TCN_STDARGS, jlong mutex)
+{
+ apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_proc_mutex_trylock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, unlock)(TCN_STDARGS, jlong mutex)
+{
+ apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_proc_mutex_unlock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Lock, destoy)(TCN_STDARGS, jlong mutex)
+{
+ apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_proc_mutex_destroy(m);
+}
+
+#if 0
+/* There is bug in APR implementing that function */
+TCN_IMPLEMENT_CALL(jint, Lock, cleanup)(TCN_STDARGS, jlong mutex)
+{
+ void *m = J2P(mutex, void *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_proc_mutex_cleanup(m);
+}
+#endif
+
+TCN_IMPLEMENT_CALL(jstring, Lock, lockfile)(TCN_STDARGS, jlong mutex)
+{
+ apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+ const char *s = apr_proc_mutex_lockfile(m);
+
+ UNREFERENCED_STDARGS;
+ if (s)
+ return AJP_TO_JSTRING(s);
+ else
+ return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Lock, name)(TCN_STDARGS, jlong mutex)
+{
+ apr_proc_mutex_t *m = J2P(mutex, apr_proc_mutex_t *);
+
+ UNREFERENCED(o);
+ return AJP_TO_JSTRING(apr_proc_mutex_name(m));
+}
+
+TCN_IMPLEMENT_CALL(jstring, Lock, defname)(TCN_STDARGS)
+{
+
+ UNREFERENCED(o);
+ return AJP_TO_JSTRING(apr_proc_mutex_defname());
+}
+
+
+
+TCN_IMPLEMENT_CALL(jlong, Global, create)(TCN_STDARGS,
+ jstring fname,
+ jint mech, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_global_mutex_t *mutex;
+ TCN_ALLOC_CSTRING(fname);
+
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_global_mutex_create(&mutex, J2S(fname),
+ (apr_lockmech_e)mech, p), mutex);
+
+cleanup:
+ TCN_FREE_CSTRING(fname);
+ return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Global, childInit)(TCN_STDARGS,
+ jstring fname,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_global_mutex_t *mutex;
+ TCN_ALLOC_CSTRING(fname);
+
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_global_mutex_child_init(&mutex,
+ J2S(fname), p), mutex);
+
+cleanup:
+ TCN_FREE_CSTRING(fname);
+ return P2J(mutex);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, lock)(TCN_STDARGS, jlong mutex)
+{
+ apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_global_mutex_lock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, trylock)(TCN_STDARGS, jlong mutex)
+{
+ apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_global_mutex_trylock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, unlock)(TCN_STDARGS, jlong mutex)
+{
+ apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t*);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_global_mutex_unlock(m);
+}
+
+TCN_IMPLEMENT_CALL(jint, Global, destoy)(TCN_STDARGS, jlong mutex)
+{
+ apr_global_mutex_t *m = J2P(mutex, apr_global_mutex_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_global_mutex_destroy(m);
+}
+
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_time.h"
+
+TCN_IMPLEMENT_CALL(void, Time, sleep)(TCN_STDARGS, jlong t)
+{
+
+ UNREFERENCED_STDARGS;
+ apr_sleep((apr_interval_time_t)t);
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, random)(TCN_STDARGS, jbyteArray buf,
+ jint len)
+{
+#if APR_HAS_RANDOM
+ apr_status_t rv;
+ jbyte *b = (*e)->GetPrimitiveArrayCritical(e, buf, NULL);
+
+ UNREFERENCED(o);
+ if ((rv = apr_generate_random_bytes((unsigned char *)b,
+ (apr_size_t)len)) == APR_SUCCESS)
+ (*e)->ReleasePrimitiveArrayCritical(e, buf, b, 0);
+ else
+ (*e)->ReleasePrimitiveArrayCritical(e, buf, b, JNI_ABORT);
+
+ if ((*e)->ExceptionCheck(e)) {
+ (*e)->ExceptionClear(e);
+ rv = APR_EGENERAL;
+ }
+ return (jint)rv;
+#else
+ return APR_ENOTIMPL;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jlong, Time, now)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ return (jlong)apr_time_now();
+}
+
+TCN_IMPLEMENT_CALL(jstring, Time, rfc822)(TCN_STDARGS, jlong t)
+{
+ char ts[APR_RFC822_DATE_LEN];
+ UNREFERENCED(o);
+ if (apr_rfc822_date(ts, J2T(t)) == APR_SUCCESS)
+ return AJP_TO_JSTRING(ts);
+ else
+ return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Time, ctime)(TCN_STDARGS, jlong t)
+{
+ char ts[APR_CTIME_LEN];
+ UNREFERENCED(o);
+ if (apr_ctime(ts, J2T(t)) == APR_SUCCESS)
+ return AJP_TO_JSTRING(ts);
+ else
+ return NULL;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_mmap.h"
+
+TCN_IMPLEMENT_CALL(jlong, Mmap, create)(TCN_STDARGS, jlong file,
+ jlong offset, jlong size,
+ jint flag, jlong pool)
+{
+#if APR_HAS_MMAP
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_mmap_t *m = NULL;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_mmap_create(&m, f, (apr_off_t)offset,
+ (apr_size_t)size,
+ (apr_uint32_t)flag, p), m);
+
+cleanup:
+ return P2J(m);
+#else
+ UNREFERENCED(o);
+ tcn_ThrowAPRException(e, APR_ENOTIMPL);
+ return 0;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jlong, Mmap, dup)(TCN_STDARGS, jlong mmap,
+ jlong pool)
+{
+#if APR_HAS_MMAP
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_mmap_t *m = J2P(mmap, apr_mmap_t *);
+ apr_mmap_t *newm = NULL;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_mmap_dup(&newm, m, p), newm);
+
+cleanup:
+ return P2J(newm);
+#else
+ UNREFERENCED(o);
+ tcn_ThrowAPRException(e, APR_ENOTIMPL);
+ return 0;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jint, Mmap, delete)(TCN_STDARGS, jlong mmap)
+{
+#if APR_HAS_MMAP
+ apr_mmap_t *m = J2P(mmap, apr_mmap_t *);
+
+ UNREFERENCED_STDARGS;
+ return apr_mmap_delete(m);
+
+#else
+ UNREFERENCED_STDARGS;
+ UNREFERENCED(mmap);
+ return APR_ENOTIMPL;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jlong, Mmap, offset)(TCN_STDARGS, jlong mmap,
+ jlong offset)
+{
+#if APR_HAS_MMAP
+ apr_mmap_t *m = J2P(mmap, apr_mmap_t *);
+ void *r;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_mmap_offset(&r, m, (apr_off_t)offset), r);
+
+cleanup:
+ return P2J(r);
+
+#else
+ UNREFERENCED(o);
+ tcn_ThrowAPRException(e, APR_ENOTIMPL);
+ return 0;
+#endif
+}
--- /dev/null
+/* Copyright 2000-2006 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/*\r
+ *\r
+ * @author Mladen Turk\r
+ * @version $Revision: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $\r
+ */\r
+\r
+#include "tcn.h"\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, join)(TCN_STDARGS,\r
+ jlong sock, jlong join,\r
+ jlong iface, jlong source)\r
+{\r
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+ apr_sockaddr_t *ja = J2P(join, apr_sockaddr_t *);\r
+ apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);\r
+ apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *);\r
+ UNREFERENCED_STDARGS;\r
+ return (jint)apr_mcast_join(s->sock, ja, ia, sa);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, leave)(TCN_STDARGS,\r
+ jlong sock, jlong addr,\r
+ jlong iface, jlong source)\r
+{\r
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+ apr_sockaddr_t *aa = J2P(addr, apr_sockaddr_t *);\r
+ apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);\r
+ apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *);\r
+ UNREFERENCED_STDARGS;\r
+ return (jint)apr_mcast_leave(s->sock, aa, ia, sa);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, hops)(TCN_STDARGS,\r
+ jlong sock, jint ttl)\r
+{\r
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+ UNREFERENCED_STDARGS;\r
+ return (jint)apr_mcast_hops(s->sock, (apr_byte_t)ttl);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, loopback)(TCN_STDARGS,\r
+ jlong sock, jboolean opt)\r
+{\r
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+ UNREFERENCED_STDARGS;\r
+ return (jint)apr_mcast_loopback(s->sock, opt == JNI_TRUE ? 1 : 0);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, ointerface)(TCN_STDARGS,\r
+ jlong sock, jlong iface)\r
+{\r
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+ apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);\r
+ UNREFERENCED_STDARGS;\r
+ return (jint)apr_mcast_interface(s->sock, ia);\r
+};\r
--- /dev/null
+/* Copyright 2000-2006 The Apache Software Foundation
+ *
+ * Licensed 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"
+
+#ifdef TCN_DO_STATISTICS
+
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t sp_created = 0;
+static volatile apr_uint32_t sp_closed = 0;
+static volatile apr_uint32_t sp_cleared = 0;
+static volatile apr_uint32_t sp_accepted = 0;
+static volatile apr_uint32_t sp_max_send = 0;
+static volatile apr_uint32_t sp_min_send = 10000000;
+static volatile apr_uint32_t sp_num_send = 0;
+static volatile apr_off_t sp_tot_send = 0;
+static volatile apr_uint32_t sp_max_recv = 0;
+static volatile apr_uint32_t sp_min_recv = 10000000;
+static volatile apr_uint32_t sp_num_recv = 0;
+static volatile apr_off_t sp_tot_recv = 0;
+static volatile apr_uint32_t sp_err_recv = 0;
+static volatile apr_uint32_t sp_tmo_recv = 0;
+static volatile apr_uint32_t sp_rst_recv = 0;
+static volatile apr_status_t sp_erl_recv = 0;
+
+static volatile apr_size_t sf_max_send = 0;
+static volatile apr_size_t sf_min_send = 10000000;
+static volatile apr_uint32_t sf_num_send = 0;
+static volatile apr_off_t sf_tot_send = 0;
+
+void sp_network_dump_statistics()
+{
+ fprintf(stderr, "Network Statistics ......\n");
+ fprintf(stderr, "Sockets created : %d\n", sp_created);
+ fprintf(stderr, "Sockets accepted : %d\n", sp_accepted);
+ fprintf(stderr, "Sockets closed : %d\n", sp_closed);
+ fprintf(stderr, "Sockets cleared : %d\n", sp_cleared);
+ fprintf(stderr, "Total send calls : %d\n", sp_num_send);
+ fprintf(stderr, "Minimum send length : %d\n", sp_min_send);
+ fprintf(stderr, "Maximum send length : %d\n", sp_max_send);
+ fprintf(stderr, "Average send length : %.2f\n", (double)sp_tot_send/(double)sp_num_send);
+ fprintf(stderr, "Total recv calls : %d\n", sp_num_recv);
+ fprintf(stderr, "Minimum recv length : %d\n", sp_min_recv);
+ fprintf(stderr, "Maximum recv length : %d\n", sp_max_recv);
+ fprintf(stderr, "Average recv length : %.2f\n", (double)sp_tot_recv/(double)sp_num_recv);
+ fprintf(stderr, "Receive timeouts : %d\n", sp_tmo_recv);
+ fprintf(stderr, "Receive errors : %d\n", sp_err_recv);
+ fprintf(stderr, "Receive resets : %d\n", sp_rst_recv);
+ fprintf(stderr, "Last receive error : %d\n", sp_erl_recv);
+
+ fprintf(stderr, "Total sendfile calls : %d\n", sf_num_send);
+ fprintf(stderr, "Minimum sendfile lenght : %" APR_SIZE_T_FMT "\n", sf_min_send);
+ fprintf(stderr, "Maximum sendfile lenght : %" APR_SIZE_T_FMT "\n", sf_max_send);
+
+}
+
+#endif /* TCN_DO_STATISTICS */
+
+static apr_status_t sp_socket_cleanup(void *data)
+{
+ tcn_socket_t *s = (tcn_socket_t *)data;
+
+ if (s->net && s->net->cleanup)
+ (*s->net->cleanup)(s->opaque);
+ if (s->sock) {
+ apr_socket_close(s->sock);
+ s->sock = NULL;
+ }
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&sp_cleared);
+#endif
+ return APR_SUCCESS;
+}
+
+#if defined(DEBUG) || defined(_DEBUG)
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_send(apr_socket_t *sock, const char *buf, apr_size_t *len)
+{
+ return apr_socket_send(sock, buf, len);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+ return apr_socket_recv(sock, buf, len);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_sendv(apr_socket_t *sock, const struct iovec *vec,
+ apr_int32_t nvec, apr_size_t *len)
+{
+ return apr_socket_sendv(sock, vec, nvec, len);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+ return apr_socket_shutdown(sock, how);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+ return apr_socket_timeout_set(sock, t);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+ return apr_socket_timeout_get(sock, t);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+ return apr_socket_opt_set(sock, opt, on);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+APR_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+ return apr_socket_opt_get(sock, opt, on);
+}
+
+#else
+#define APR_socket_send apr_socket_send
+#define APR_socket_recv apr_socket_recv
+#define APR_socket_sendv apr_socket_sendv
+#define APR_socket_shutdown apr_socket_shutdown
+#define APR_socket_timeout_set apr_socket_timeout_set
+#define APR_socket_timeout_get apr_socket_timeout_get
+#define APR_socket_opt_set apr_socket_opt_set
+#define APR_socket_opt_get apr_socket_opt_get
+#endif
+
+static tcn_nlayer_t apr_socket_layer = {
+ TCN_SOCKET_APR,
+ NULL,
+ NULL,
+ APR_socket_shutdown,
+ APR_socket_opt_get,
+ APR_socket_opt_set,
+ APR_socket_timeout_get,
+ APR_socket_timeout_set,
+ APR_socket_send,
+ APR_socket_sendv,
+ APR_socket_recv
+};
+
+TCN_IMPLEMENT_CALL(jlong, Socket, create)(TCN_STDARGS, jint family,
+ jint type, jint protocol,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_socket_t *s = NULL;
+ tcn_socket_t *a = NULL;
+ apr_int32_t f, t;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+ GET_S_FAMILY(f, family);
+ GET_S_TYPE(t, type);
+
+ if (family >= 0) {
+ TCN_THROW_IF_ERR(apr_socket_create(&s,
+ f, t, protocol, p), a);
+ }
+#ifdef TCN_DO_STATISTICS
+ sp_created++;
+#endif
+ a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+ TCN_CHECK_ALLOCATED(a);
+ a->sock = s;
+ a->pool = p;
+ if (family >= 0)
+ a->net = &apr_socket_layer;
+ a->opaque = s;
+ apr_pool_cleanup_register(p, (const void *)a,
+ sp_socket_cleanup,
+ apr_pool_cleanup_null);
+
+cleanup:
+ return P2J(a);
+
+}
+
+TCN_IMPLEMENT_CALL(void, Socket, destroy)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ apr_pool_destroy(s->pool);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, pool)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_pool_t *n;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_THROW_IF_ERR(apr_pool_create(&n, s->pool), n);
+cleanup:
+ return P2J(n);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, get)(TCN_STDARGS, jlong sock, jint what)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+
+ switch (what) {
+ case TCN_SOCKET_GET_POOL:
+ return P2J(s->pool);
+ break;
+ case TCN_SOCKET_GET_IMPL:
+ return P2J(s->opaque);
+ break;
+ case TCN_SOCKET_GET_APRS:
+ return P2J(s->sock);
+ break;
+ case TCN_SOCKET_GET_TYPE:
+ return (jlong)(s->net->type);
+ break;
+ }
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, shutdown)(TCN_STDARGS, jlong sock,
+ jint how)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ return (jint)(*s->net->shutdown)(s->opaque, how);
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, close)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ jint rv = APR_SUCCESS;
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&sp_closed);
+#endif
+ if (s->net && s->net->close) {
+ rv = (*s->net->close)(s->opaque);
+ s->net = NULL;
+ }
+ if (s->sock) {
+ rv = (jint)apr_socket_close(s->sock);
+ s->sock = NULL;
+ }
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, bind)(TCN_STDARGS, jlong sock,
+ jlong sa)
+{
+ jint rv = APR_SUCCESS;
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_sockaddr_t *a = J2P(sa, apr_sockaddr_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->sock != NULL);
+ rv = (jint)apr_socket_bind(s->sock, a);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, listen)(TCN_STDARGS, jlong sock,
+ jint backlog)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->sock != NULL);
+ return (jint)apr_socket_listen(s->sock, backlog);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, acceptx)(TCN_STDARGS, jlong sock,
+ jlong pool)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_socket_t *n = NULL;
+ tcn_socket_t *a = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ if (s->net->type == TCN_SOCKET_APR) {
+ TCN_ASSERT(s->sock != NULL);
+ TCN_THROW_IF_ERR(apr_socket_accept(&n, s->sock, p), n);
+ }
+ else {
+ tcn_ThrowAPRException(e, APR_ENOTIMPL);
+ goto cleanup;
+ }
+ if (n) {
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&sp_accepted);
+#endif
+ a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+ TCN_CHECK_ALLOCATED(a);
+ a->sock = n;
+ a->pool = p;
+ a->net = &apr_socket_layer;
+ a->opaque = n;
+ apr_pool_cleanup_register(p, (const void *)a,
+ sp_socket_cleanup,
+ apr_pool_cleanup_null);
+ }
+
+cleanup:
+ return P2J(a);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, accept)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_pool_t *p = NULL;
+ apr_socket_t *n = NULL;
+ tcn_socket_t *a = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+ if (s->net->type == TCN_SOCKET_APR) {
+ TCN_ASSERT(s->sock != NULL);
+ TCN_THROW_IF_ERR(apr_socket_accept(&n, s->sock, p), n);
+ }
+ else {
+ tcn_ThrowAPRException(e, APR_ENOTIMPL);
+ goto cleanup;
+ }
+ if (n) {
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&sp_accepted);
+#endif
+ a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+ TCN_CHECK_ALLOCATED(a);
+ a->sock = n;
+ a->pool = p;
+ a->net = &apr_socket_layer;
+ a->opaque = n;
+ apr_pool_cleanup_register(p, (const void *)a,
+ sp_socket_cleanup,
+ apr_pool_cleanup_null);
+ }
+ return P2J(a);
+cleanup:
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, connect)(TCN_STDARGS, jlong sock,
+ jlong sa)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_sockaddr_t *a = J2P(sa, apr_sockaddr_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->sock != NULL);
+ return (jint)apr_socket_connect(s->sock, a);
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, send)(TCN_STDARGS, jlong sock,
+ jbyteArray buf, jint offset, jint tosend)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_size_t nbytes = (apr_size_t)tosend;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+#ifdef TCN_DO_STATISTICS
+ sp_max_send = TCN_MAX(sp_max_send, nbytes);
+ sp_min_send = TCN_MIN(sp_min_send, nbytes);
+ sp_tot_send += nbytes;
+ sp_num_send++;
+#endif
+
+ if (tosend <= TCN_BUFFER_SZ) {
+ jbyte sb[TCN_BUFFER_SZ];
+ (*e)->GetByteArrayRegion(e, buf, offset, tosend, &sb[0]);
+ ss = (*s->net->send)(s->opaque, sb, &nbytes);
+ }
+ else {
+ jbyte *sb = (jbyte *)malloc(nbytes);
+ if (sb == NULL)
+ return -APR_ENOMEM;
+ (*e)->GetByteArrayRegion(e, buf, offset, tosend, sb);
+ ss = (*s->net->send)(s->opaque, sb, &nbytes);
+ free(sb);
+ }
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(void, Socket, setsbb)(TCN_STDARGS, jlong sock,
+ jobject buf)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ if (buf)
+ s->jsbbuff = (char *)(*e)->GetDirectBufferAddress(e, buf);
+ else
+ s->jsbbuff = NULL;
+}
+
+TCN_IMPLEMENT_CALL(void, Socket, setrbb)(TCN_STDARGS, jlong sock,
+ jobject buf)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ if (buf)
+ s->jrbbuff = (char *)(*e)->GetDirectBufferAddress(e, buf);
+ else
+ s->jrbbuff = NULL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendb)(TCN_STDARGS, jlong sock,
+ jobject buf, jint offset, jint len)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_size_t nbytes = (apr_size_t)len;
+ apr_size_t sent = 0;
+ char *bytes;
+ apr_status_t ss = APR_SUCCESS;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ TCN_ASSERT(buf != NULL);
+#ifdef TCN_DO_STATISTICS
+ sp_max_send = TCN_MAX(sp_max_send, nbytes);
+ sp_min_send = TCN_MIN(sp_min_send, nbytes);
+ sp_tot_send += nbytes;
+ sp_num_send++;
+#endif
+
+ bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+
+ while (sent < nbytes) {
+ apr_size_t wr = nbytes - sent;
+ ss = (*s->net->send)(s->opaque, bytes + offset + sent, &wr);
+ if (ss != APR_SUCCESS)
+ break;
+ sent += wr;
+ }
+
+ if (ss == APR_SUCCESS)
+ return (jint)sent;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendbb)(TCN_STDARGS, jlong sock,
+ jint offset, jint len)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_size_t nbytes = (apr_size_t)len;
+ apr_size_t sent = 0;
+ apr_status_t ss = APR_SUCCESS;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ TCN_ASSERT(s->jsbbuff != NULL);
+#ifdef TCN_DO_STATISTICS
+ sp_max_send = TCN_MAX(sp_max_send, nbytes);
+ sp_min_send = TCN_MIN(sp_min_send, nbytes);
+ sp_tot_send += nbytes;
+ sp_num_send++;
+#endif
+
+ while (sent < nbytes) {
+ apr_size_t wr = nbytes - sent;
+ ss = (*s->net->send)(s->opaque, s->jsbbuff + offset + sent, &wr);
+ if (ss != APR_SUCCESS)
+ break;
+ sent += wr;
+ }
+ if (ss == APR_SUCCESS)
+ return (jint)sent;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendv)(TCN_STDARGS, jlong sock,
+ jobjectArray bufs)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ jsize nvec;
+ jsize i;
+ struct iovec vec[APR_MAX_IOVEC_SIZE];
+ jobject ba[APR_MAX_IOVEC_SIZE];
+ apr_size_t written = 0;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+
+ nvec = (*e)->GetArrayLength(e, bufs);
+ if (nvec >= APR_MAX_IOVEC_SIZE)
+ return (jint)(-APR_ENOMEM);
+
+ for (i = 0; i < nvec; i++) {
+ ba[i] = (*e)->GetObjectArrayElement(e, bufs, i);
+ vec[i].iov_len = (*e)->GetArrayLength(e, ba[i]);
+ vec[i].iov_base = (*e)->GetByteArrayElements(e, ba[i], NULL);
+ }
+
+ ss = (*s->net->sendv)(s->opaque, vec, nvec, &written);
+
+ for (i = 0; i < nvec; i++) {
+ (*e)->ReleaseByteArrayElements(e, ba[i], vec[i].iov_base, JNI_ABORT);
+ }
+ if (ss == APR_SUCCESS)
+ return (jint)written;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, sendto)(TCN_STDARGS, jlong sock,
+ jlong where, jint flag,
+ jbyteArray buf, jint offset, jint tosend)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_sockaddr_t *w = J2P(where, apr_sockaddr_t *);
+ apr_size_t nbytes = (apr_size_t)tosend;
+ jbyte *bytes;
+ apr_int32_t nb;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->sock != NULL);
+
+ bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+ TCN_ASSERT(bytes != NULL);
+ apr_socket_opt_get(s->sock, APR_SO_NONBLOCK, &nb);
+ if (nb)
+ bytes = (*e)->GetPrimitiveArrayCritical(e, buf, NULL);
+ else
+ bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+ ss = apr_socket_sendto(s->sock, w, flag, (char *)(bytes + offset), &nbytes);
+
+ if (nb)
+ (*e)->ReleasePrimitiveArrayCritical(e, buf, bytes, 0);
+ else
+ (*e)->ReleaseByteArrayElements(e, buf, bytes, JNI_ABORT);
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recv)(TCN_STDARGS, jlong sock,
+ jbyteArray buf, jint offset, jint toread)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_size_t nbytes = (apr_size_t)toread;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+
+ if (toread <= TCN_BUFFER_SZ) {
+ char sb[TCN_BUFFER_SZ];
+
+ if ((ss = (*s->net->recv)(s->opaque, sb, &nbytes)) == APR_SUCCESS)
+ (*e)->SetByteArrayRegion(e, buf, offset, (jsize)nbytes, (jbyte*)&sb[0]);
+ }
+ else {
+ jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+ if ((ss = (*s->net->recv)(s->opaque, (char*)(bytes + offset),
+ &nbytes)) == APR_SUCCESS)
+ (*e)->ReleaseByteArrayElements(e, buf, bytes,
+ nbytes ? 0 : JNI_ABORT);
+ }
+#ifdef TCN_DO_STATISTICS
+ if (ss == APR_SUCCESS) {
+ sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+ sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+ sp_tot_recv += nbytes;
+ sp_num_recv++;
+ }
+ else {
+ if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+ APR_STATUS_IS_TIMEUP(ss))
+ sp_tmo_recv++;
+ else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+ APR_STATUS_IS_ECONNRESET(ss) ||
+ APR_STATUS_IS_EOF(ss))
+ sp_rst_recv++;
+ else {
+ sp_err_recv++;
+ sp_erl_recv = ss;
+ }
+ }
+#endif
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvt)(TCN_STDARGS, jlong sock,
+ jbyteArray buf, jint offset,
+ jint toread, jlong timeout)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_size_t nbytes = (apr_size_t)toread;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ TCN_ASSERT(buf != NULL);
+
+ if ((ss = (*s->net->timeout_set)(s->opaque, J2T(timeout))) != APR_SUCCESS)
+ goto cleanup;
+ if (toread <= TCN_BUFFER_SZ) {
+ jbyte sb[TCN_BUFFER_SZ];
+ if ((ss = (*s->net->recv)(s->opaque, sb, &nbytes)) == APR_SUCCESS)
+ (*e)->SetByteArrayRegion(e, buf, offset, (jsize)nbytes, &sb[0]);
+ }
+ else {
+ jbyte *sb = (jbyte *)malloc(nbytes);
+ if (sb == NULL)
+ return -APR_ENOMEM;
+ if ((ss = (*s->net->recv)(s->opaque, sb, &nbytes)) == APR_SUCCESS)
+ (*e)->SetByteArrayRegion(e, buf, offset, (jsize)nbytes, &sb[0]);
+ free(sb);
+ }
+#ifdef TCN_DO_STATISTICS
+ if (ss == APR_SUCCESS) {
+ sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+ sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+ sp_tot_recv += nbytes;
+ sp_num_recv++;
+ }
+ else {
+ if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+ APR_STATUS_IS_TIMEUP(ss))
+ sp_tmo_recv++;
+ else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+ APR_STATUS_IS_ECONNRESET(ss) ||
+ APR_STATUS_IS_EOF(ss))
+ sp_rst_recv++;
+ else {
+ sp_err_recv++;
+ sp_erl_recv = ss;
+ }
+ }
+#endif
+cleanup:
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvb)(TCN_STDARGS, jlong sock,
+ jobject buf, jint offset, jint len)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_status_t ss;
+ apr_size_t nbytes = (apr_size_t)len;
+ char *bytes;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ TCN_ASSERT(buf != NULL);
+
+ bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+ TCN_ASSERT(bytes != NULL);
+ ss = (*s->net->recv)(s->opaque, bytes + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+ if (ss == APR_SUCCESS) {
+ sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+ sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+ sp_tot_recv += nbytes;
+ sp_num_recv++;
+ }
+ else {
+ if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+ APR_STATUS_IS_TIMEUP(ss))
+ sp_tmo_recv++;
+ else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+ APR_STATUS_IS_ECONNRESET(ss) ||
+ APR_STATUS_IS_EOF(ss))
+ sp_rst_recv++;
+ else {
+ sp_err_recv++;
+ sp_erl_recv = ss;
+ }
+ }
+#endif
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvbb)(TCN_STDARGS, jlong sock,
+ jint offset, jint len)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_status_t ss;
+ apr_size_t nbytes = (apr_size_t)len;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ TCN_ASSERT(s->jrbbuff != NULL);
+
+ ss = (*s->net->recv)(s->opaque, s->jrbbuff + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+ if (ss == APR_SUCCESS) {
+ sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+ sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+ sp_tot_recv += nbytes;
+ sp_num_recv++;
+ }
+ else {
+ if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+ APR_STATUS_IS_TIMEUP(ss))
+ sp_tmo_recv++;
+ else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+ APR_STATUS_IS_ECONNRESET(ss) ||
+ APR_STATUS_IS_EOF(ss))
+ sp_rst_recv++;
+ else {
+ sp_err_recv++;
+ sp_erl_recv = ss;
+ }
+ }
+#endif
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvbt)(TCN_STDARGS, jlong sock,
+ jobject buf, jint offset,
+ jint len, jlong timeout)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_status_t ss;
+ apr_size_t nbytes = (apr_size_t)len;
+ char *bytes;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(buf != NULL);
+ TCN_ASSERT(s->opaque != NULL);
+
+ bytes = (char *)(*e)->GetDirectBufferAddress(e, buf);
+ TCN_ASSERT(bytes != NULL);
+
+ if ((ss = (*s->net->timeout_set)(s->opaque, J2T(timeout))) != APR_SUCCESS)
+ return -(jint)ss;
+ ss = (*s->net->recv)(s->opaque, bytes + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+ if (ss == APR_SUCCESS) {
+ sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+ sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+ sp_tot_recv += nbytes;
+ sp_num_recv++;
+ }
+ else {
+ if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+ APR_STATUS_IS_TIMEUP(ss))
+ sp_tmo_recv++;
+ else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+ APR_STATUS_IS_ECONNRESET(ss) ||
+ APR_STATUS_IS_EOF(ss))
+ sp_rst_recv++;
+ else {
+ sp_err_recv++;
+ sp_erl_recv = ss;
+ }
+ }
+#endif
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvbbt)(TCN_STDARGS, jlong sock,
+ jint offset,
+ jint len, jlong timeout)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_status_t ss;
+ apr_size_t nbytes = (apr_size_t)len;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->jrbbuff != NULL);
+ TCN_ASSERT(s->opaque != NULL);
+
+
+ if ((ss = (*s->net->timeout_set)(s->opaque, J2T(timeout))) != APR_SUCCESS)
+ return -(jint)ss;
+ ss = (*s->net->recv)(s->opaque, s->jrbbuff + offset, &nbytes);
+#ifdef TCN_DO_STATISTICS
+ if (ss == APR_SUCCESS) {
+ sp_max_recv = TCN_MAX(sp_max_recv, nbytes);
+ sp_min_recv = TCN_MIN(sp_min_recv, nbytes);
+ sp_tot_recv += nbytes;
+ sp_num_recv++;
+ }
+ else {
+ if (APR_STATUS_IS_ETIMEDOUT(ss) ||
+ APR_STATUS_IS_TIMEUP(ss))
+ sp_tmo_recv++;
+ else if (APR_STATUS_IS_ECONNABORTED(ss) ||
+ APR_STATUS_IS_ECONNRESET(ss) ||
+ APR_STATUS_IS_EOF(ss))
+ sp_rst_recv++;
+ else {
+ sp_err_recv++;
+ sp_erl_recv = ss;
+ }
+ }
+#endif
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, recvfrom)(TCN_STDARGS, jlong from,
+ jlong sock, jint flags,
+ jbyteArray buf, jint offset, jint toread)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_sockaddr_t *f = J2P(from, apr_sockaddr_t *);
+ apr_size_t nbytes = (apr_size_t)toread;
+ jbyte *bytes = (*e)->GetByteArrayElements(e, buf, NULL);
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->sock != NULL);
+ TCN_ASSERT(buf != NULL);
+ ss = apr_socket_recvfrom(f, s->sock, (apr_int32_t)flags, (char*)(bytes + offset), &nbytes);
+
+ (*e)->ReleaseByteArrayElements(e, buf, bytes,
+ nbytes ? 0 : JNI_ABORT);
+ if (ss == APR_SUCCESS)
+ return (jint)nbytes;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jint)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, optSet)(TCN_STDARGS, jlong sock,
+ jint opt, jint on)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ if (!s->sock)
+ return APR_EINVAL;
+ else
+ return (jint)(*s->net->opt_set)(s->opaque, (apr_int32_t)opt, (apr_int32_t)on);
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, optGet)(TCN_STDARGS, jlong sock,
+ jint opt)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_int32_t on = 0;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ if (s->sock)
+ tcn_ThrowAPRException(e, APR_EINVAL);
+ else {
+ TCN_THROW_IF_ERR((*s->net->opt_get)(s->opaque, (apr_int32_t)opt,
+ &on), on);
+ }
+cleanup:
+ return (jint)on;
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, timeoutSet)(TCN_STDARGS, jlong sock,
+ jlong timeout)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ return (jint)(*s->net->timeout_set)(s->opaque, J2T(timeout));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, timeoutGet)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_interval_time_t timeout;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->opaque != NULL);
+ TCN_THROW_IF_ERR((*s->net->timeout_get)(s->opaque, &timeout), timeout);
+cleanup:
+ return (jlong)timeout;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Socket, atmark)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_int32_t mark;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(s->sock != NULL);
+
+ if (apr_socket_atmark(s->sock, &mark) != APR_SUCCESS)
+ return JNI_FALSE;
+ return mark ? JNI_TRUE : JNI_FALSE;
+}
+
+#if APR_HAS_SENDFILE
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfile)(TCN_STDARGS, jlong sock,
+ jlong file,
+ jobjectArray headers,
+ jobjectArray trailers,
+ jlong offset, jlong len,
+ jint flags)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_file_t *f = J2P(file, apr_file_t *);
+ jsize nh = 0;
+ jsize nt = 0;
+ jsize i;
+ struct iovec hvec[APR_MAX_IOVEC_SIZE];
+ struct iovec tvec[APR_MAX_IOVEC_SIZE];
+ jobject hba[APR_MAX_IOVEC_SIZE];
+ jobject tba[APR_MAX_IOVEC_SIZE];
+ apr_off_t off = (apr_off_t)offset;
+ apr_size_t written = (apr_size_t)len;
+ apr_hdtr_t hdrs;
+ apr_status_t ss;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(file != 0);
+
+ if (s->net->type != TCN_SOCKET_APR)
+ return (jint)(-APR_ENOTIMPL);
+ if (headers)
+ nh = (*e)->GetArrayLength(e, headers);
+ if (trailers)
+ nt = (*e)->GetArrayLength(e, trailers);
+ /* Check for overflow */
+ if (nh >= APR_MAX_IOVEC_SIZE || nt >= APR_MAX_IOVEC_SIZE)
+ return (jint)(-APR_ENOMEM);
+
+ for (i = 0; i < nh; i++) {
+ hba[i] = (*e)->GetObjectArrayElement(e, headers, i);
+ hvec[i].iov_len = (*e)->GetArrayLength(e, hba[i]);
+ hvec[i].iov_base = (*e)->GetByteArrayElements(e, hba[i], NULL);
+ }
+ for (i = 0; i < nt; i++) {
+ tba[i] = (*e)->GetObjectArrayElement(e, trailers, i);
+ tvec[i].iov_len = (*e)->GetArrayLength(e, tba[i]);
+ tvec[i].iov_base = (*e)->GetByteArrayElements(e, tba[i], NULL);
+ }
+ hdrs.headers = &hvec[0];
+ hdrs.numheaders = nh;
+ hdrs.trailers = &tvec[0];
+ hdrs.numtrailers = nt;
+
+
+ ss = apr_socket_sendfile(s->sock, f, &hdrs, &off, &written, (apr_int32_t)flags);
+
+#ifdef TCN_DO_STATISTICS
+ sf_max_send = TCN_MAX(sf_max_send, written);
+ sf_min_send = TCN_MIN(sf_min_send, written);
+ sf_tot_send += written;
+ sf_num_send++;
+#endif
+
+ for (i = 0; i < nh; i++) {
+ (*e)->ReleaseByteArrayElements(e, hba[i], hvec[i].iov_base, JNI_ABORT);
+ }
+
+ for (i = 0; i < nt; i++) {
+ (*e)->ReleaseByteArrayElements(e, tba[i], tvec[i].iov_base, JNI_ABORT);
+ }
+ /* Return Number of bytes actually sent,
+ * including headers, file, and trailers
+ */
+ if (ss == APR_SUCCESS)
+ return (jlong)written;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jlong)ss;
+ }
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfilen)(TCN_STDARGS, jlong sock,
+ jlong file,
+ jlong offset, jlong len,
+ jint flags)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_file_t *f = J2P(file, apr_file_t *);
+ apr_off_t off = (apr_off_t)offset;
+ apr_size_t written = (apr_size_t)len;
+ apr_hdtr_t hdrs;
+ apr_status_t ss;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ TCN_ASSERT(file != 0);
+
+ if (s->net->type != TCN_SOCKET_APR)
+ return (jint)(-APR_ENOTIMPL);
+
+ hdrs.headers = NULL;
+ hdrs.numheaders = 0;
+ hdrs.trailers = NULL;
+ hdrs.numtrailers = 0;
+
+
+ ss = apr_socket_sendfile(s->sock, f, &hdrs, &off, &written, (apr_int32_t)flags);
+
+#ifdef TCN_DO_STATISTICS
+ sf_max_send = TCN_MAX(sf_max_send, written);
+ sf_min_send = TCN_MIN(sf_min_send, written);
+ sf_tot_send += written;
+ sf_num_send++;
+#endif
+
+ /* Return Number of bytes actually sent,
+ * including headers, file, and trailers
+ */
+ if (ss == APR_SUCCESS)
+ return (jlong)written;
+ else {
+ TCN_ERROR_WRAP(ss);
+ return -(jlong)ss;
+ }
+}
+
+#else /* APR_HAS_SENDIFLE */
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfile)(TCN_STDARGS, jlong sock,
+ jlong file,
+ jobjectArray headers,
+ jobjectArray trailers,
+ jlong offset, jlong len,
+ jint flags)
+{
+
+ UNREFERENCED_STDARGS;
+ UNREFERENCED(sock);
+ UNREFERENCED(file);
+ UNREFERENCED(headers);
+ UNREFERENCED(trailers);
+ UNREFERENCED(offset);
+ UNREFERENCED(len);
+ UNREFERENCED(flags);
+ return -(jlong)APR_ENOTIMPL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Socket, sendfilen)(TCN_STDARGS, jlong sock,
+ jlong file,
+ jlong offset, jlong len,
+ jint flags)
+{
+ UNREFERENCED_STDARGS;
+ UNREFERENCED(sock);
+ UNREFERENCED(file);
+ UNREFERENCED(offset);
+ UNREFERENCED(len);
+ UNREFERENCED(flags);
+ return -(jlong)APR_ENOTIMPL;
+}
+
+#endif /* APR_HAS_SENDIFLE */
+
+
+TCN_IMPLEMENT_CALL(jint, Socket, acceptfilter)(TCN_STDARGS,
+ jlong sock,
+ jstring name,
+ jstring args)
+{
+#if APR_HAS_SO_ACCEPTFILTER
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ TCN_ALLOC_CSTRING(name);
+ TCN_ALLOC_CSTRING(args);
+ apr_status_t rv;
+
+
+ UNREFERENCED(o);
+ rv = apr_socket_accept_filter(s->sock, J2S(name),
+ J2S(args) ? J2S(args) : "");
+ TCN_FREE_CSTRING(name);
+ TCN_FREE_CSTRING(args);
+ return (jint)rv;
+#else
+ UNREFERENCED_STDARGS;
+ UNREFERENCED(sock);
+ UNREFERENCED(name);
+ UNREFERENCED(args);
+ return (jint)APR_ENOTIMPL;
+#endif
+}
+
+TCN_IMPLEMENT_CALL(jint, Socket, dataSet)(TCN_STDARGS, jlong sock,
+ jstring key, jobject data)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ apr_status_t rv = APR_SUCCESS;
+ TCN_ALLOC_CSTRING(key);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ rv = apr_socket_data_set(s->sock, data, J2S(key), NULL);
+ TCN_FREE_CSTRING(key);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Socket, dataGet)(TCN_STDARGS, jlong socket,
+ jstring key)
+{
+ tcn_socket_t *s = J2P(socket, tcn_socket_t *);
+ TCN_ALLOC_CSTRING(key);
+ void *rv = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ if (apr_socket_data_get(&rv, J2S(key), s->sock) != APR_SUCCESS) {
+ rv = NULL;
+ }
+ TCN_FREE_CSTRING(key);
+ return rv;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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"
+
+TCN_IMPLEMENT_CALL(jstring, OS, defaultEncoding)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+
+ UNREFERENCED(o);
+ return AJP_TO_JSTRING(apr_os_default_encoding(p));
+}
+
+TCN_IMPLEMENT_CALL(jstring, OS, localeEncoding)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+
+ UNREFERENCED(o);
+ return AJP_TO_JSTRING(apr_os_locale_encoding(p));
+}
+
--- /dev/null
+/* Copyright 2000-2006 The Apache Software Foundation
+ *
+ * Licensed 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_poll.h"
+
+
+#ifdef TCN_DO_STATISTICS
+static int sp_created = 0;
+static int sp_destroyed = 0;
+static int sp_cleared = 0;
+#endif
+
+/* Internal poll structure for queryset
+ */
+
+typedef struct tcn_pollset {
+ apr_pool_t *pool;
+ apr_int32_t nelts;
+ apr_int32_t nalloc;
+ apr_pollset_t *pollset;
+ jlong *set;
+ apr_pollfd_t *socket_set;
+ apr_interval_time_t *socket_ttl;
+ apr_interval_time_t max_ttl;
+#ifdef TCN_DO_STATISTICS
+ int sp_added;
+ int sp_max_count;
+ int sp_poll;
+ int sp_polled;
+ int sp_max_polled;
+ int sp_remove;
+ int sp_removed;
+ int sp_maintained;
+ int sp_max_maintained;
+ int sp_err_poll;
+ int sp_poll_timeout;
+ int sp_overflow;
+ int sp_equals;
+ int sp_eintr;
+#endif
+} tcn_pollset_t;
+
+#ifdef TCN_DO_STATISTICS
+static void sp_poll_statistics(tcn_pollset_t *p)
+{
+ fprintf(stderr, "Pollset Statistics ......\n");
+ fprintf(stderr, "Number of added sockets : %d\n", p->sp_added);
+ fprintf(stderr, "Max. number of sockets : %d\n", p->sp_max_count);
+ fprintf(stderr, "Poll calls : %d\n", p->sp_poll);
+ fprintf(stderr, "Poll timeouts : %d\n", p->sp_poll_timeout);
+ fprintf(stderr, "Poll errors : %d\n", p->sp_err_poll);
+ fprintf(stderr, "Poll overflows : %d\n", p->sp_overflow);
+ fprintf(stderr, "Polled sockets : %d\n", p->sp_polled);
+ fprintf(stderr, "Max. Polled sockets : %d\n", p->sp_max_polled);
+ fprintf(stderr, "Poll remove : %d\n", p->sp_remove);
+ fprintf(stderr, "Total removed : %d\n", p->sp_removed);
+ fprintf(stderr, "Maintained : %d\n", p->sp_maintained);
+ fprintf(stderr, "Max. maintained : %d\n", p->sp_max_maintained);
+ fprintf(stderr, "Number of duplicates : %d\n", p->sp_equals);
+ fprintf(stderr, "Number of interrupts : %d\n", p->sp_eintr);
+
+}
+
+static apr_status_t sp_poll_cleanup(void *data)
+{
+ sp_cleared++;
+ sp_poll_statistics(data);
+ return APR_SUCCESS;
+}
+
+void sp_poll_dump_statistics()
+{
+ fprintf(stderr, "Poll Statistics .........\n");
+ fprintf(stderr, "Polls created : %d\n", sp_created);
+ fprintf(stderr, "Polls destroyed : %d\n", sp_destroyed);
+ fprintf(stderr, "Polls cleared : %d\n", sp_cleared);
+}
+#endif
+
+TCN_IMPLEMENT_CALL(jlong, Poll, create)(TCN_STDARGS, jint size,
+ jlong pool, jint flags,
+ jlong ttl)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_pollset_t *pollset = NULL;
+ tcn_pollset_t *tps = NULL;
+ apr_uint32_t f = (apr_uint32_t)flags;
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if (f & APR_POLLSET_THREADSAFE) {
+ apr_status_t rv = apr_pollset_create(&pollset, (apr_uint32_t)size, p, f);
+ if (rv == APR_ENOTIMPL)
+ f &= ~APR_POLLSET_THREADSAFE;
+ else if (rv != APR_SUCCESS) {
+ tcn_ThrowAPRException(e, rv);
+ goto cleanup;
+ }
+ }
+ if (pollset == NULL) {
+ TCN_THROW_IF_ERR(apr_pollset_create(&pollset,
+ (apr_uint32_t)size, p, f), pollset);
+ }
+ tps = apr_pcalloc(p, sizeof(tcn_pollset_t));
+ TCN_CHECK_ALLOCATED(tps);
+ tps->pollset = pollset;
+ tps->set = apr_palloc(p, size * sizeof(jlong) * 2);
+ TCN_CHECK_ALLOCATED(tps->set);
+ tps->socket_set = apr_palloc(p, size * sizeof(apr_pollfd_t));
+ TCN_CHECK_ALLOCATED(tps->socket_set);
+ tps->socket_ttl = apr_palloc(p, size * sizeof(apr_interval_time_t));
+ TCN_CHECK_ALLOCATED(tps->socket_ttl);
+ tps->nelts = 0;
+ tps->nalloc = size;
+ tps->pool = p;
+ tps->max_ttl = J2T(ttl);
+#ifdef TCN_DO_STATISTICS
+ sp_created++;
+ apr_pool_cleanup_register(p, (const void *)tps,
+ sp_poll_cleanup,
+ apr_pool_cleanup_null);
+#endif
+cleanup:
+ return P2J(tps);
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, destroy)(TCN_STDARGS, jlong pollset)
+{
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(pollset != 0);
+#ifdef TCN_DO_STATISTICS
+ sp_destroyed++;
+ apr_pool_cleanup_kill(p->pool, p, sp_poll_cleanup);
+ sp_poll_statistics(p);
+#endif
+ return (jint)apr_pollset_destroy(p->pollset);
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, add)(TCN_STDARGS, jlong pollset,
+ jlong socket, jint reqevents)
+{
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+ tcn_socket_t *s = J2P(socket, tcn_socket_t *);
+ apr_pollfd_t fd;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(socket != 0);
+
+ if (p->nelts == p->nalloc) {
+#ifdef TCN_DO_STATISTICS
+ p->sp_overflow++;
+#endif
+ return APR_ENOMEM;
+ }
+ memset(&fd, 0, sizeof(apr_pollfd_t));
+ fd.desc_type = APR_POLL_SOCKET;
+ fd.reqevents = (apr_int16_t)reqevents;
+ fd.desc.s = s->sock;
+ fd.client_data = s;
+ if (p->max_ttl > 0)
+ p->socket_ttl[p->nelts] = apr_time_now();
+ else
+ p->socket_ttl[p->nelts] = 0;
+
+ p->socket_set[p->nelts] = fd;
+ p->nelts++;
+#ifdef TCN_DO_STATISTICS
+ p->sp_added++;
+ p->sp_max_count = TCN_MAX(p->sp_max_count, p->sp_added);
+#endif
+ return (jint)apr_pollset_add(p->pollset, &fd);
+}
+
+static apr_status_t do_remove(tcn_pollset_t *p, const apr_pollfd_t *fd)
+{
+ apr_int32_t i;
+
+ for (i = 0; i < p->nelts; i++) {
+ if (fd->desc.s == p->socket_set[i].desc.s) {
+ /* Found an instance of the fd: remove this and any other copies */
+ apr_int32_t dst = i;
+ apr_int32_t old_nelts = p->nelts;
+ p->nelts--;
+#ifdef TCN_DO_STATISTICS
+ p->sp_removed++;
+#endif
+ for (i++; i < old_nelts; i++) {
+ if (fd->desc.s == p->socket_set[i].desc.s) {
+#ifdef TCN_DO_STATISTICS
+ p->sp_equals++;
+#endif
+ p->nelts--;
+ }
+ else {
+ p->socket_set[dst] = p->socket_set[i];
+ dst++;
+ }
+ }
+ break;
+ }
+ }
+ return apr_pollset_remove(p->pollset, fd);
+}
+
+static void remove_all(tcn_pollset_t *p)
+{
+ apr_int32_t i;
+ for (i = 0; i < p->nelts; i++) {
+ apr_pollset_remove(p->pollset, &(p->socket_set[i]));
+#ifdef TCN_DO_STATISTICS
+ p->sp_removed++;
+#endif
+ }
+ p->nelts = 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, remove)(TCN_STDARGS, jlong pollset,
+ jlong socket)
+{
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+ tcn_socket_t *s = J2P(socket, tcn_socket_t *);
+ apr_pollfd_t fd;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(socket != 0);
+
+ memset(&fd, 0, sizeof(apr_pollfd_t));
+ fd.desc_type = APR_POLL_SOCKET;
+ fd.desc.s = s->sock;
+ fd.reqevents = APR_POLLIN | APR_POLLOUT;
+#ifdef TCN_DO_STATISTICS
+ p->sp_remove++;
+#endif
+
+ return (jint)do_remove(p, &fd);
+}
+
+
+TCN_IMPLEMENT_CALL(jint, Poll, poll)(TCN_STDARGS, jlong pollset,
+ jlong timeout, jlongArray set,
+ jboolean remove)
+{
+ const apr_pollfd_t *fd = NULL;
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+ apr_int32_t i, num = 0;
+ apr_status_t rv = APR_SUCCESS;
+ apr_interval_time_t ptime = J2T(timeout);
+ UNREFERENCED(o);
+ TCN_ASSERT(pollset != 0);
+
+#ifdef TCN_DO_STATISTICS
+ p->sp_poll++;
+#endif
+
+ if (ptime > 0 && p->max_ttl >= 0) {
+ apr_time_t now = apr_time_now();
+
+ /* Find the minimum timeout */
+ for (i = 0; i < p->nelts; i++) {
+ apr_interval_time_t t = now - p->socket_ttl[i];
+ if (t >= p->max_ttl) {
+ ptime = 0;
+ break;
+ }
+ else {
+ ptime = TCN_MIN(p->max_ttl - t, ptime);
+ }
+ }
+ }
+ else if (ptime < 0)
+ ptime = 0;
+ for (;;) {
+ rv = apr_pollset_poll(p->pollset, ptime, &num, &fd);
+ if (rv != APR_SUCCESS) {
+ if (APR_STATUS_IS_EINTR(rv)) {
+#ifdef TCN_DO_STATISTICS
+ p->sp_eintr++;
+#endif
+ continue;
+ }
+ TCN_ERROR_WRAP(rv);
+#ifdef TCN_DO_STATISTICS
+ if (rv == TCN_TIMEUP)
+ p->sp_poll_timeout++;
+ else
+ p->sp_err_poll++;
+#endif
+ num = (apr_int32_t)(-rv);
+ }
+ break;
+ }
+ if (num > 0) {
+#ifdef TCN_DO_STATISTICS
+ p->sp_polled += num;
+ p->sp_max_polled = TCN_MAX(p->sp_max_polled, num);
+#endif
+ for (i = 0; i < num; i++) {
+ p->set[i*2+0] = (jlong)(fd->rtnevents);
+ p->set[i*2+1] = P2J(fd->client_data);
+ if (remove)
+ do_remove(p, fd);
+ fd ++;
+ }
+ (*e)->SetLongArrayRegion(e, set, 0, num * 2, p->set);
+ }
+
+ return (jint)num;
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, maintain)(TCN_STDARGS, jlong pollset,
+ jlongArray set, jboolean remove)
+{
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+ apr_int32_t i = 0, num = 0;
+ apr_time_t now = apr_time_now();
+ apr_pollfd_t fd;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pollset != 0);
+
+ /* Check for timeout sockets */
+ if (p->max_ttl > 0) {
+ for (i = 0; i < p->nelts; i++) {
+ if ((now - p->socket_ttl[i]) >= p->max_ttl) {
+ fd = p->socket_set[i];
+ p->set[num++] = P2J(fd.client_data);
+ }
+ }
+ if (remove && num) {
+ memset(&fd, 0, sizeof(apr_pollfd_t));
+#ifdef TCN_DO_STATISTICS
+ p->sp_maintained += num;
+ p->sp_max_maintained = TCN_MAX(p->sp_max_maintained, num);
+#endif
+ for (i = 0; i < num; i++) {
+ fd.desc_type = APR_POLL_SOCKET;
+ fd.reqevents = APR_POLLIN | APR_POLLOUT;
+ fd.desc.s = (J2P(p->set[i], tcn_socket_t *))->sock;
+ do_remove(p, &fd);
+ }
+ }
+ }
+ else if (p->max_ttl == 0) {
+ for (i = 0; i < p->nelts; i++) {
+ fd = p->socket_set[i];
+ p->set[num++] = P2J(fd.client_data);
+ }
+ if (remove) {
+ remove_all(p);
+#ifdef TCN_DO_STATISTICS
+ p->sp_maintained += num;
+ p->sp_max_maintained = TCN_MAX(p->sp_max_maintained, num);
+#endif
+ }
+ }
+ if (num)
+ (*e)->SetLongArrayRegion(e, set, 0, num, p->set);
+ return (jint)num;
+}
+
+TCN_IMPLEMENT_CALL(void, Poll, setTtl)(TCN_STDARGS, jlong pollset,
+ jlong ttl)
+{
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+ UNREFERENCED_STDARGS;
+ p->max_ttl = J2T(ttl);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Poll, getTtl)(TCN_STDARGS, jlong pollset)
+{
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+ UNREFERENCED_STDARGS;
+ return (jlong)p->max_ttl;
+}
+
+TCN_IMPLEMENT_CALL(jint, Poll, pollset)(TCN_STDARGS, jlong pollset,
+ jlongArray set)
+{
+ tcn_pollset_t *p = J2P(pollset, tcn_pollset_t *);
+ apr_int32_t i = 0;
+ apr_pollfd_t fd;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pollset != 0);
+
+ for (i = 0; i < p->nelts; i++) {
+ p->socket_set[i].rtnevents = APR_POLLHUP | APR_POLLIN;
+ fd = p->socket_set[i];
+ p->set[i*2+0] = (jlong)(fd.rtnevents);
+ p->set[i*2+1] = P2J(fd.client_data);
+ }
+ if (p->nelts)
+ (*e)->SetLongArrayRegion(e, set, 0, p->nelts * 2, p->set);
+ return (jint)p->nelts;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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"
+
+extern apr_pool_t *tcn_global_pool;
+
+static apr_status_t generic_pool_cleanup(void *data)
+{
+ apr_status_t rv = APR_SUCCESS;
+ tcn_callback_t *cb = (tcn_callback_t *)data;
+
+ if (data) {
+ JNIEnv *env;
+ tcn_get_java_env(&env);
+ if (!TCN_IS_NULL(env, cb->obj)) {
+ rv = (*(env))->CallIntMethod(env, cb->obj, cb->mid[0],
+ NULL);
+ TCN_UNLOAD_CLASS(env, cb->obj);
+ }
+ free(cb);
+ }
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, create)(TCN_STDARGS, jlong parent)
+{
+ apr_pool_t *p = J2P(parent, apr_pool_t *);
+ apr_pool_t *n;
+
+ UNREFERENCED(o);
+ /* Make sure our global pool is accessor for all pools */
+ if (p == NULL)
+ p = tcn_global_pool;
+ TCN_THROW_IF_ERR(apr_pool_create(&n, p), n);
+cleanup:
+ return P2J(n);
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, clear)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(pool != 0);
+ apr_pool_clear(p);
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, destroy)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(pool != 0);
+ apr_pool_destroy(p);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, parentGet)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(pool != 0);
+ return P2J(apr_pool_parent_get(p));
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Pool, isAncestor)(TCN_STDARGS, jlong a, jlong b)
+{
+ apr_pool_t *pa = J2P(a, apr_pool_t *);
+ apr_pool_t *pb = J2P(b, apr_pool_t *);
+ UNREFERENCED_STDARGS;
+ return apr_pool_is_ancestor(pa, pb) ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, palloc)(TCN_STDARGS, jlong pool, jint size)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ UNREFERENCED_STDARGS;
+ return P2J(apr_palloc(p, (apr_size_t)size));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, pcalloc)(TCN_STDARGS, jlong pool, jint size)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ UNREFERENCED_STDARGS;
+ return P2J(apr_pcalloc(p, (apr_size_t)size));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Pool, cleanupRegister)(TCN_STDARGS, jlong pool,
+ jobject obj)
+{
+ 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) {
+ TCN_THROW_OS_ERROR(e);
+ return 0;
+ }
+ cls = (*e)->GetObjectClass(e, obj);
+ cb->obj = (*e)->NewGlobalRef(e, obj);
+ cb->mid[0] = (*e)->GetMethodID(e, cls, "callback", "()I");
+
+ apr_pool_cleanup_register(p, (const void *)cb,
+ generic_pool_cleanup,
+ apr_pool_cleanup_null);
+
+ return P2J(cb);
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, cleanupKill)(TCN_STDARGS, jlong pool,
+ jlong data)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ tcn_callback_t *cb = J2P(data, tcn_callback_t *);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+ apr_pool_cleanup_kill(p, cb, generic_pool_cleanup);
+ (*e)->DeleteGlobalRef(e, cb->obj);
+ free(cb);
+}
+
+TCN_IMPLEMENT_CALL(jobject, Pool, alloc)(TCN_STDARGS, jlong pool,
+ jint size)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_size_t sz = (apr_size_t)size;
+ void *mem;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if ((mem = apr_palloc(p, sz)) != NULL)
+ return (*e)->NewDirectByteBuffer(e, mem, (jlong)sz);
+ else
+ return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Pool, calloc)(TCN_STDARGS, jlong pool,
+ jint size)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_size_t sz = (apr_size_t)size;
+ void *mem;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if ((mem = apr_pcalloc(p, sz)) != NULL)
+ return (*e)->NewDirectByteBuffer(e, mem, (jlong)sz);
+ else
+ return NULL;
+}
+
+static apr_status_t generic_pool_data_cleanup(void *data)
+{
+ apr_status_t rv = APR_SUCCESS;
+ 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 rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Pool, dataSet)(TCN_STDARGS, jlong pool,
+ jstring key, jobject data)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_status_t rv = APR_SUCCESS;
+ void *old = NULL;
+ TCN_ALLOC_CSTRING(key);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if (apr_pool_userdata_get(&old, J2S(key), p) == APR_SUCCESS) {
+ if (old)
+ apr_pool_cleanup_run(p, old, generic_pool_data_cleanup);
+ }
+ if (data) {
+ JNIEnv *e;
+ tcn_callback_t *cb = (tcn_callback_t *)malloc(sizeof(tcn_callback_t));
+ tcn_get_java_env(&e);
+ cb->obj = (*e)->NewGlobalRef(e, data);
+ if ((rv = apr_pool_userdata_set(cb, J2S(key), generic_pool_data_cleanup,
+ p)) != APR_SUCCESS) {
+ (*e)->DeleteGlobalRef(e, cb->obj);
+ free(cb);
+ }
+ }
+ else {
+ /* Clear the exiting user data */
+ rv = apr_pool_userdata_set(NULL, J2S(key), NULL, p);
+ }
+ TCN_FREE_CSTRING(key);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Pool, dataGet)(TCN_STDARGS, jlong pool,
+ jstring key)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ void *old = NULL;
+ TCN_ALLOC_CSTRING(key);
+ jobject rv = NULL;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(pool != 0);
+
+ if (apr_pool_userdata_get(&old, J2S(key), p) == APR_SUCCESS) {
+ if (old) {
+ tcn_callback_t *cb = (tcn_callback_t *)old;
+ rv = cb->obj;
+ }
+ }
+ TCN_FREE_CSTRING(key);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(void, Pool, cleanupForExec)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ apr_pool_cleanup_for_exec();
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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;
+ 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
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_shm.h"
+
+TCN_IMPLEMENT_CALL(jlong, Shm, create)(TCN_STDARGS, jlong reqsize,
+ jstring filename,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ const char *fname = NULL;
+ apr_shm_t *shm;
+
+
+ UNREFERENCED(o);
+ if (filename)
+ fname = (const char *)((*e)->GetStringUTFChars(e, filename, 0));
+ TCN_THROW_IF_ERR(apr_shm_create(&shm, (apr_size_t)reqsize,
+ fname, p), shm);
+
+cleanup:
+ if (fname)
+ (*e)->ReleaseStringUTFChars(e, filename, fname);
+ return P2J(shm);
+}
+
+TCN_IMPLEMENT_CALL(jint, Shm, remove)(TCN_STDARGS,
+ jstring filename,
+ jlong pool)
+{
+ apr_status_t rv;
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ TCN_ALLOC_CSTRING(filename);
+
+
+ UNREFERENCED(o);
+ rv = apr_shm_remove(J2S(filename), p);
+ TCN_FREE_CSTRING(filename);
+
+ return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Shm, destroy)(TCN_STDARGS, jlong shm)
+{
+ apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_shm_destroy(s);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Shm, attach)(TCN_STDARGS,
+ jstring filename,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ const char *fname = NULL;
+ apr_shm_t *shm;
+
+
+ UNREFERENCED(o);
+ if (filename)
+ fname = (const char *)((*e)->GetStringUTFChars(e, filename, 0));
+ TCN_THROW_IF_ERR(apr_shm_attach(&shm, fname, p), shm);
+
+cleanup:
+ if (fname)
+ (*e)->ReleaseStringUTFChars(e, filename, fname);
+ return P2J(shm);
+}
+
+TCN_IMPLEMENT_CALL(jint, Shm, detach)(TCN_STDARGS, jlong shm)
+{
+ apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jint)apr_shm_detach(s);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Shm, baseaddr)(TCN_STDARGS, jlong shm)
+{
+ apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+ UNREFERENCED_STDARGS;
+ return P2J(apr_shm_baseaddr_get(s));
+}
+
+TCN_IMPLEMENT_CALL(jlong, Shm, size)(TCN_STDARGS, jlong shm)
+{
+ apr_shm_t *s = J2P(shm, apr_shm_t *);
+
+ UNREFERENCED_STDARGS;
+ return (jlong)apr_shm_size_get(s);
+}
+
+TCN_IMPLEMENT_CALL(jobject, Shm, buffer)(TCN_STDARGS, jlong shm)
+{
+ apr_shm_t *s = J2P(shm, apr_shm_t *);
+ jlong sz = (jlong)apr_shm_size_get(s);
+ void *a;
+
+ UNREFERENCED(o);
+
+ if ((a = apr_shm_baseaddr_get(s)) != NULL)
+ return (*e)->NewDirectByteBuffer(e, a, sz);
+ else
+ return NULL;
+}
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_file_io.h"
+#include "apr_thread_mutex.h"
+#include "apr_atomic.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+static int ssl_initialized = 0;
+static char *ssl_global_rand_file = NULL;
+extern apr_pool_t *tcn_global_pool;
+
+ENGINE *tcn_ssl_engine = NULL;
+void *SSL_temp_keys[SSL_TMP_KEY_MAX];
+tcn_pass_cb_t tcn_password_callback;
+
+/*
+ * Handle the Temporary RSA Keys and DH Params
+ */
+
+#define SSL_TMP_KEY_FREE(type, idx) \
+ if (SSL_temp_keys[idx]) { \
+ type##_free((type *)SSL_temp_keys[idx]); \
+ SSL_temp_keys[idx] = NULL; \
+ } else (void)(0)
+
+#define SSL_TMP_KEYS_FREE(type) \
+ SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_512); \
+ SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_1024); \
+ SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_2048); \
+ SSL_TMP_KEY_FREE(type, SSL_TMP_KEY_##type##_4096)
+
+#define SSL_TMP_KEY_INIT_RSA(bits) \
+ ssl_tmp_key_init_rsa(bits, SSL_TMP_KEY_RSA_##bits)
+
+#define SSL_TMP_KEY_INIT_DH(bits) \
+ ssl_tmp_key_init_dh(bits, SSL_TMP_KEY_DH_##bits)
+
+#define SSL_TMP_KEYS_INIT(R) \
+ SSL_temp_keys[SSL_TMP_KEY_RSA_2048] = NULL; \
+ SSL_temp_keys[SSL_TMP_KEY_RSA_4096] = NULL; \
+ R |= SSL_TMP_KEY_INIT_RSA(512); \
+ R |= SSL_TMP_KEY_INIT_RSA(1024); \
+ R |= SSL_TMP_KEY_INIT_DH(512); \
+ R |= SSL_TMP_KEY_INIT_DH(1024); \
+ R |= SSL_TMP_KEY_INIT_DH(2048); \
+ R |= SSL_TMP_KEY_INIT_DH(4096)
+
+static int ssl_tmp_key_init_rsa(int bits, int idx)
+{
+ if (!(SSL_temp_keys[idx] =
+ RSA_generate_key(bits, RSA_F4, NULL, NULL)))
+ return 1;
+ else
+ return 0;
+}
+
+static int ssl_tmp_key_init_dh(int bits, int idx)
+{
+ if (!(SSL_temp_keys[idx] =
+ SSL_dh_get_tmp_param(bits)))
+ return 1;
+ else
+ return 0;
+}
+
+
+TCN_IMPLEMENT_CALL(jint, SSL, version)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ return OPENSSL_VERSION_NUMBER;
+}
+
+TCN_IMPLEMENT_CALL(jstring, SSL, versionString)(TCN_STDARGS)
+{
+ UNREFERENCED(o);
+ return AJP_TO_JSTRING(OPENSSL_VERSION_TEXT);
+}
+
+/*
+ * the various processing hooks
+ */
+static apr_status_t ssl_init_cleanup(void *data)
+{
+ UNREFERENCED(data);
+
+ if (!ssl_initialized)
+ return APR_SUCCESS;
+ ssl_initialized = 0;
+
+ if (tcn_password_callback.cb.obj) {
+ JNIEnv *env;
+ tcn_get_java_env(&env);
+ TCN_UNLOAD_CLASS(env,
+ tcn_password_callback.cb.obj);
+ }
+
+ SSL_TMP_KEYS_FREE(RSA);
+ SSL_TMP_KEYS_FREE(DH);
+ /*
+ * Try to kill the internals of the SSL library.
+ */
+#if OPENSSL_VERSION_NUMBER >= 0x00907001
+ /* Corresponds to OPENSSL_load_builtin_modules():
+ * XXX: borrowed from apps.h, but why not CONF_modules_free()
+ * which also invokes CONF_modules_finish()?
+ */
+ CONF_modules_unload(1);
+#endif
+ /* Corresponds to SSL_library_init: */
+ EVP_cleanup();
+#if HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+ ENGINE_cleanup();
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00907001
+ CRYPTO_cleanup_all_ex_data();
+#endif
+ ERR_remove_state(0);
+
+ /* Don't call ERR_free_strings here; ERR_load_*_strings only
+ * actually load the error strings once per process due to static
+ * variable abuse in OpenSSL. */
+
+ /*
+ * TODO: determine somewhere we can safely shove out diagnostics
+ * (when enabled) at this late stage in the game:
+ * CRYPTO_mem_leaks_fp(stderr);
+ */
+ return APR_SUCCESS;
+}
+
+#ifndef OPENSSL_NO_ENGINE
+/* Try to load an engine in a shareable library */
+static ENGINE *ssl_try_load_engine(const char *engine)
+{
+ ENGINE *e = ENGINE_by_id("dynamic");
+ if (e) {
+ if (!ENGINE_ctrl_cmd_string(e, "SO_PATH", engine, 0)
+ || !ENGINE_ctrl_cmd_string(e, "LOAD", NULL, 0)) {
+ ENGINE_free(e);
+ e = NULL;
+ }
+ }
+ return e;
+}
+#endif
+
+/*
+ * To ensure thread-safetyness in OpenSSL
+ */
+
+static apr_thread_mutex_t **ssl_lock_cs;
+static int ssl_lock_num_locks;
+
+static void ssl_thread_lock(int mode, int type,
+ const char *file, int line)
+{
+ UNREFERENCED(file);
+ UNREFERENCED(line);
+ if (type < ssl_lock_num_locks) {
+ if (mode & CRYPTO_LOCK) {
+ apr_thread_mutex_lock(ssl_lock_cs[type]);
+ }
+ else {
+ apr_thread_mutex_unlock(ssl_lock_cs[type]);
+ }
+ }
+}
+
+static unsigned long ssl_thread_id(void)
+{
+ /* OpenSSL needs this to return an unsigned long. On OS/390, the pthread
+ * id is a structure twice that big. Use the TCB pointer instead as a
+ * unique unsigned long.
+ */
+#ifdef __MVS__
+ struct PSA {
+ char unmapped[540];
+ unsigned long PSATOLD;
+ } *psaptr = 0;
+
+ return psaptr->PSATOLD;
+#else
+ return (unsigned long)(apr_os_thread_current());
+#endif
+}
+
+static apr_status_t ssl_thread_cleanup(void *data)
+{
+ UNREFERENCED(data);
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_id_callback(NULL);
+ /* Let the registered mutex cleanups do their own thing
+ */
+ return APR_SUCCESS;
+}
+
+static void ssl_thread_setup(apr_pool_t *p)
+{
+ int i;
+
+ ssl_lock_num_locks = CRYPTO_num_locks();
+ ssl_lock_cs = apr_palloc(p, ssl_lock_num_locks * sizeof(*ssl_lock_cs));
+
+ for (i = 0; i < ssl_lock_num_locks; i++) {
+ apr_thread_mutex_create(&(ssl_lock_cs[i]),
+ APR_THREAD_MUTEX_DEFAULT, p);
+ }
+
+ CRYPTO_set_id_callback(ssl_thread_id);
+ CRYPTO_set_locking_callback(ssl_thread_lock);
+
+ apr_pool_cleanup_register(p, NULL, ssl_thread_cleanup,
+ apr_pool_cleanup_null);
+}
+
+static int ssl_rand_choosenum(int l, int h)
+{
+ int i;
+ char buf[50];
+
+ apr_snprintf(buf, sizeof(buf), "%.0f",
+ (((double)(rand()%RAND_MAX)/RAND_MAX)*(h-l)));
+ i = atoi(buf)+1;
+ if (i < l) i = l;
+ if (i > h) i = h;
+ return i;
+}
+
+static int ssl_rand_load_file(const char *file)
+{
+ char buffer[APR_PATH_MAX];
+ int n;
+
+ if (file == NULL)
+ file = ssl_global_rand_file;
+
+ if (file == NULL)
+ file = RAND_file_name(buffer, sizeof(buffer));
+ else if ((n = RAND_egd(file)) > 0) {
+ return n;
+ }
+ if (file && (n = RAND_load_file(file, -1)) > 0)
+ return n;
+ else
+ return -1;
+}
+
+/*
+ * writes a number of random bytes (currently 1024) to
+ * file which can be used to initialize the PRNG by calling
+ * RAND_load_file() in a later session
+ */
+static int ssl_rand_save_file(const char *file)
+{
+ char buffer[APR_PATH_MAX];
+ int n;
+
+ if (file == NULL)
+ file = RAND_file_name(buffer, sizeof(buffer));
+ else if ((n = RAND_egd(file)) > 0) {
+ return 0;
+ }
+ if (file == NULL || !RAND_write_file(file))
+ return 0;
+ else
+ return 1;
+}
+
+int SSL_rand_seed(const char *file)
+{
+ unsigned char stackdata[256];
+ static volatile apr_uint32_t counter = 0;
+
+ if (ssl_rand_load_file(file) < 0) {
+ int n;
+ struct {
+ apr_time_t t;
+ pid_t p;
+ unsigned long i;
+ apr_uint32_t u;
+ } _ssl_seed;
+ if (counter == 0) {
+ apr_generate_random_bytes(stackdata, 256);
+ RAND_seed(stackdata, 128);
+ }
+ _ssl_seed.t = apr_time_now();
+ _ssl_seed.p = getpid();
+ _ssl_seed.i = ssl_thread_id();
+ apr_atomic_inc32(&counter);
+ _ssl_seed.u = counter;
+ RAND_seed((unsigned char *)&_ssl_seed, sizeof(_ssl_seed));
+ /*
+ * seed in some current state of the run-time stack (128 bytes)
+ */
+ n = ssl_rand_choosenum(0, sizeof(stackdata)-128-1);
+ RAND_seed(stackdata + n, 128);
+ }
+ return RAND_status();
+}
+
+static int ssl_rand_make(const char *file, int len, int base64)
+{
+ int r;
+ int num = len;
+ BIO *out = NULL;
+
+ out = BIO_new(BIO_s_file());
+ if (out == NULL)
+ return 0;
+ if ((r = BIO_write_filename(out, (char *)file)) < 0) {
+ BIO_free_all(out);
+ return 0;
+ }
+ if (base64) {
+ BIO *b64 = BIO_new(BIO_f_base64());
+ if (b64 == NULL) {
+ BIO_free_all(out);
+ return 0;
+ }
+ out = BIO_push(b64, out);
+ }
+ while (num > 0) {
+ unsigned char buf[4096];
+ int len = num;
+ if (len > sizeof(buf))
+ len = sizeof(buf);
+ r = RAND_bytes(buf, len);
+ if (r <= 0) {
+ BIO_free_all(out);
+ return 0;
+ }
+ BIO_write(out, buf, len);
+ num -= len;
+ }
+ BIO_flush(out);
+ BIO_free_all(out);
+ return 1;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSL, initialize)(TCN_STDARGS, jstring engine)
+{
+ int r = 0;
+ TCN_ALLOC_CSTRING(engine);
+
+ UNREFERENCED(o);
+ if (!tcn_global_pool) {
+ TCN_FREE_CSTRING(engine);
+ return (jint)APR_EINVAL;
+ }
+ /* Check if already initialized */
+ if (ssl_initialized++) {
+ TCN_FREE_CSTRING(engine);
+ return (jint)APR_SUCCESS;
+ }
+ if (SSLeay() < 0x0090700L) {
+ TCN_FREE_CSTRING(engine);
+ return (jint)APR_EINVAL;
+ }
+ /* We must register the library in full, to ensure our configuration
+ * code can successfully test the SSL environment.
+ */
+ CRYPTO_malloc_init();
+ ERR_load_crypto_strings();
+ SSL_load_error_strings();
+ SSL_library_init();
+#if HAVE_ENGINE_LOAD_BUILTIN_ENGINES
+ ENGINE_load_builtin_engines();
+#endif
+#if OPENSSL_VERSION_NUMBER >= 0x00907001
+ OPENSSL_load_builtin_modules();
+#endif
+
+#ifndef OPENSSL_NO_ENGINE
+ if (J2S(engine)) {
+ ENGINE *ee = NULL;
+ apr_status_t err = APR_SUCCESS;
+ if(strcmp(J2S(engine), "auto") == 0) {
+ ENGINE_register_all_complete();
+ }
+ else {
+ if ((ee = ENGINE_by_id(J2S(engine))) == NULL
+ && (ee = ssl_try_load_engine(J2S(engine))) == NULL)
+ err = APR_ENOTIMPL;
+ else {
+ if (strcmp(J2S(engine), "chil") == 0)
+ ENGINE_ctrl(ee, ENGINE_CTRL_CHIL_SET_FORKCHECK, 1, 0, 0);
+ if (!ENGINE_set_default(ee, ENGINE_METHOD_ALL))
+ err = APR_ENOTIMPL;
+ }
+ /* Free our "structural" reference. */
+ if (ee)
+ ENGINE_free(ee);
+ }
+ if (err != APR_SUCCESS) {
+ TCN_FREE_CSTRING(engine);
+ ssl_init_cleanup(NULL);
+ return (jint)err;
+ }
+ tcn_ssl_engine = ee;
+ }
+#endif
+
+ memset(&tcn_password_callback, 0, sizeof(tcn_pass_cb_t));
+ /* Initialize PRNG
+ * This will in most cases call the builtin
+ * low entropy seed.
+ */
+ SSL_rand_seed(NULL);
+ /* For SSL_get_app_data2() at request time */
+ SSL_init_app_data2_idx();
+
+ SSL_TMP_KEYS_INIT(r);
+ if (r) {
+ TCN_FREE_CSTRING(engine);
+ ssl_init_cleanup(NULL);
+ return APR_ENOTIMPL;
+ }
+ /*
+ * Let us cleanup the ssl library when the library is unloaded
+ */
+ apr_pool_cleanup_register(tcn_global_pool, NULL,
+ ssl_init_cleanup,
+ apr_pool_cleanup_null);
+ /* Initialize thread support */
+ ssl_thread_setup(tcn_global_pool);
+ TCN_FREE_CSTRING(engine);
+ return (jint)APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, randLoad)(TCN_STDARGS, jstring file)
+{
+ TCN_ALLOC_CSTRING(file);
+ int r;
+ UNREFERENCED(o);
+ r = SSL_rand_seed(J2S(file));
+ TCN_FREE_CSTRING(file);
+ return r ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, randSave)(TCN_STDARGS, jstring file)
+{
+ TCN_ALLOC_CSTRING(file);
+ int r;
+ UNREFERENCED(o);
+ r = ssl_rand_save_file(J2S(file));
+ TCN_FREE_CSTRING(file);
+ return r ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, randMake)(TCN_STDARGS, jstring file,
+ jint length, jboolean base64)
+{
+ TCN_ALLOC_CSTRING(file);
+ int r;
+ UNREFERENCED(o);
+ r = ssl_rand_make(J2S(file), length, base64);
+ TCN_FREE_CSTRING(file);
+ return r ? JNI_TRUE : JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(void, SSL, randSet)(TCN_STDARGS, jstring file)
+{
+ TCN_ALLOC_CSTRING(file);
+ UNREFERENCED(o);
+ if (J2S(file)) {
+ ssl_global_rand_file = apr_pstrdup(tcn_global_pool, J2S(file));
+ }
+ TCN_FREE_CSTRING(file);
+}
+/* OpenSSL Java Stream BIO */
+
+typedef struct {
+ int refcount;
+ apr_pool_t *pool;
+ tcn_callback_t cb;
+} BIO_JAVA;
+
+
+static apr_status_t generic_bio_cleanup(void *data)
+{
+ BIO *b = (BIO *)data;
+
+ if (b) {
+ BIO_free(b);
+ }
+ return APR_SUCCESS;
+}
+
+void SSL_BIO_close(BIO *bi)
+{
+ if (bi == NULL)
+ return;
+ if (bi->ptr != NULL && (bi->flags & SSL_BIO_FLAG_CALLBACK)) {
+ BIO_JAVA *j = (BIO_JAVA *)bi->ptr;
+ j->refcount--;
+ if (j->refcount == 0) {
+ if (j->pool)
+ apr_pool_cleanup_run(j->pool, bi, generic_bio_cleanup);
+ else
+ BIO_free(bi);
+ }
+ }
+ else
+ BIO_free(bi);
+}
+
+void SSL_BIO_doref(BIO *bi)
+{
+ if (bi == NULL)
+ return;
+ if (bi->ptr != NULL && (bi->flags & SSL_BIO_FLAG_CALLBACK)) {
+ BIO_JAVA *j = (BIO_JAVA *)bi->ptr;
+ j->refcount++;
+ }
+}
+
+
+static int jbs_new(BIO *bi)
+{
+ BIO_JAVA *j;
+
+ if ((j = OPENSSL_malloc(sizeof(BIO_JAVA))) == NULL)
+ return 0;
+ j->pool = NULL;
+ j->refcount = 1;
+ bi->shutdown = 1;
+ bi->init = 0;
+ bi->num = -1;
+ bi->ptr = (char *)j;
+
+ return 1;
+}
+
+static int jbs_free(BIO *bi)
+{
+ if (bi == NULL)
+ return 0;
+ if (bi->ptr != NULL) {
+ BIO_JAVA *j = (BIO_JAVA *)bi->ptr;
+ if (bi->init) {
+ JNIEnv *e = NULL;
+ bi->init = 0;
+ tcn_get_java_env(&e);
+ TCN_UNLOAD_CLASS(e, j->cb.obj);
+ }
+ OPENSSL_free(bi->ptr);
+ }
+ bi->ptr = NULL;
+ return 1;
+}
+
+static int jbs_write(BIO *b, const char *in, int inl)
+{
+ jint ret = 0;
+ if (b->init && in != NULL) {
+ BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+ JNIEnv *e = NULL;
+ jbyteArray jb = (*e)->NewByteArray(e, inl);
+ tcn_get_java_env(&e);
+ if (!(*e)->ExceptionOccurred(e)) {
+ (*e)->SetByteArrayRegion(e, jb, 0, inl, (jbyte *)in);
+ ret = (*e)->CallIntMethod(e, j->cb.obj,
+ j->cb.mid[0], jb);
+ (*e)->ReleaseByteArrayElements(e, jb, (jbyte *)in, JNI_ABORT);
+ (*e)->DeleteLocalRef(e, jb);
+ }
+ }
+ return ret;
+}
+
+static int jbs_read(BIO *b, char *out, int outl)
+{
+ jint ret = 0;
+ if (b->init && out != NULL) {
+ BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+ JNIEnv *e = NULL;
+ jbyteArray jb = (*e)->NewByteArray(e, outl);
+ tcn_get_java_env(&e);
+ if (!(*e)->ExceptionOccurred(e)) {
+ ret = (*e)->CallIntMethod(e, j->cb.obj,
+ j->cb.mid[1], jb);
+ if (ret > 0) {
+ jbyte *jout = (*e)->GetPrimitiveArrayCritical(e, jb, NULL);
+ memcpy(out, jout, ret);
+ (*e)->ReleasePrimitiveArrayCritical(e, jb, jout, 0);
+ }
+ (*e)->DeleteLocalRef(e, jb);
+ }
+ }
+ return ret;
+}
+
+static int jbs_puts(BIO *b, const char *in)
+{
+ int ret = 0;
+ if (b->init && in != NULL) {
+ BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+ JNIEnv *e = NULL;
+ tcn_get_java_env(&e);
+ ret = (*e)->CallIntMethod(e, j->cb.obj,
+ j->cb.mid[2],
+ tcn_new_string(e, in));
+ }
+ return ret;
+}
+
+static int jbs_gets(BIO *b, char *out, int outl)
+{
+ int ret = 0;
+ if (b->init && out != NULL) {
+ BIO_JAVA *j = (BIO_JAVA *)b->ptr;
+ JNIEnv *e = NULL;
+ jobject o;
+ tcn_get_java_env(&e);
+ if ((o = (*e)->CallObjectMethod(e, j->cb.obj,
+ j->cb.mid[3], (jint)(outl - 1)))) {
+ TCN_ALLOC_CSTRING(o);
+ if (J2S(o)) {
+ int l = (int)strlen(J2S(o));
+ if (l < outl) {
+ strcpy(out, J2S(o));
+ ret = outl;
+ }
+ }
+ TCN_FREE_CSTRING(o);
+ }
+ }
+ return ret;
+}
+
+static long jbs_ctrl(BIO *b, int cmd, long num, void *ptr)
+{
+ return 0;
+}
+
+static BIO_METHOD jbs_methods = {
+ BIO_TYPE_FILE,
+ "Java Callback",
+ jbs_write,
+ jbs_read,
+ jbs_puts,
+ jbs_gets,
+ jbs_ctrl,
+ jbs_new,
+ jbs_free,
+ NULL
+};
+
+static BIO_METHOD *BIO_jbs()
+{
+ return(&jbs_methods);
+}
+
+TCN_IMPLEMENT_CALL(jlong, SSL, newBIO)(TCN_STDARGS, jlong pool,
+ jobject callback)
+{
+ BIO *bio = NULL;
+ BIO_JAVA *j;
+ jclass cls;
+
+ UNREFERENCED(o);
+
+ if ((bio = BIO_new(BIO_jbs())) == NULL) {
+ tcn_ThrowException(e, "Create BIO failed");
+ goto init_failed;
+ }
+ j = (BIO_JAVA *)bio->ptr;
+ if ((j = (BIO_JAVA *)bio->ptr) == NULL) {
+ tcn_ThrowException(e, "Create BIO failed");
+ goto init_failed;
+ }
+ j->pool = J2P(pool, apr_pool_t *);
+ if (j->pool) {
+ apr_pool_cleanup_register(j->pool, (const void *)bio,
+ generic_bio_cleanup,
+ apr_pool_cleanup_null);
+ }
+
+ cls = (*e)->GetObjectClass(e, callback);
+ j->cb.mid[0] = (*e)->GetMethodID(e, cls, "write", "([B)I");
+ j->cb.mid[1] = (*e)->GetMethodID(e, cls, "read", "([B)I");
+ j->cb.mid[2] = (*e)->GetMethodID(e, cls, "puts", "(Ljava/lang/String;)I");
+ j->cb.mid[3] = (*e)->GetMethodID(e, cls, "gets", "(I)Ljava/lang/String;");
+ /* TODO: Check if method id's are valid */
+ j->cb.obj = (*e)->NewGlobalRef(e, callback);
+
+ bio->init = 1;
+ bio->flags = SSL_BIO_FLAG_CALLBACK;
+ return P2J(bio);
+init_failed:
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSL, closeBIO)(TCN_STDARGS, jlong bio)
+{
+ BIO *b = J2P(bio, BIO *);
+ UNREFERENCED_STDARGS;
+ SSL_BIO_close(b);
+ return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(void, SSL, setPasswordCallback)(TCN_STDARGS,
+ jobject callback)
+{
+ jclass cls;
+
+ UNREFERENCED(o);
+ if (tcn_password_callback.cb.obj) {
+ TCN_UNLOAD_CLASS(e,
+ tcn_password_callback.cb.obj);
+ }
+ cls = (*e)->GetObjectClass(e, callback);
+ tcn_password_callback.cb.mid[0] = (*e)->GetMethodID(e, cls, "callback",
+ "(Ljava/lang/String;)Ljava/lang/String;");
+ /* TODO: Check if method id is valid */
+ tcn_password_callback.cb.obj = (*e)->NewGlobalRef(e, callback);
+
+}
+
+TCN_IMPLEMENT_CALL(void, SSL, setPassword)(TCN_STDARGS, jstring password)
+{
+ TCN_ALLOC_CSTRING(password);
+ UNREFERENCED(o);
+ if (J2S(password)) {
+ strncpy(tcn_password_callback.password, J2S(password), SSL_MAX_PASSWORD_LEN);
+ tcn_password_callback.password[SSL_MAX_PASSWORD_LEN-1] = '\0';
+ }
+ TCN_FREE_CSTRING(password);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, generateRSATempKey)(TCN_STDARGS, jint idx)
+{
+ int r = 1;
+ UNREFERENCED_STDARGS;
+ SSL_TMP_KEY_FREE(RSA, idx);
+ switch (idx) {
+ case SSL_TMP_KEY_RSA_512:
+ r = SSL_TMP_KEY_INIT_RSA(512);
+ break;
+ case SSL_TMP_KEY_RSA_1024:
+ r = SSL_TMP_KEY_INIT_RSA(1024);
+ break;
+ case SSL_TMP_KEY_RSA_2048:
+ r = SSL_TMP_KEY_INIT_RSA(2048);
+ break;
+ case SSL_TMP_KEY_RSA_4096:
+ r = SSL_TMP_KEY_INIT_RSA(4096);
+ break;
+ }
+ return r ? JNI_FALSE : JNI_TRUE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSL, loadDSATempKey)(TCN_STDARGS, jint idx,
+ jstring file)
+{
+ jboolean r = JNI_FALSE;
+ TCN_ALLOC_CSTRING(file);
+ DH *dh;
+ UNREFERENCED(o);
+
+ if (!J2S(file))
+ return JNI_FALSE;
+ SSL_TMP_KEY_FREE(DSA, idx);
+ if ((dh = SSL_dh_get_param_from_file(J2S(file)))) {
+ SSL_temp_keys[idx] = dh;
+ r = JNI_TRUE;
+ }
+ TCN_FREE_CSTRING(file);
+ return r;
+}
+
+TCN_IMPLEMENT_CALL(jstring, SSL, getLastError)(TCN_STDARGS)
+{
+ char buf[256];
+ UNREFERENCED(o);
+ ERR_error_string(ERR_get_error(), buf);
+ return tcn_new_string(e, buf);
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL Context wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision$, $Date$
+ */
+
+#include "tcn.h"
+
+#include "apr_file_io.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+static apr_status_t ssl_context_cleanup(void *data)
+{
+ tcn_ssl_ctxt_t *c = (tcn_ssl_ctxt_t *)data;
+ if (c) {
+ int i;
+ if (c->crl)
+ X509_STORE_free(c->crl);
+ c->crl = NULL;
+ if (c->ctx)
+ SSL_CTX_free(c->ctx);
+ c->ctx = NULL;
+ for (i = 0; i < SSL_AIDX_MAX; i++) {
+ if (c->certs[i]) {
+ X509_free(c->certs[i]);
+ c->certs[i] = NULL;
+ }
+ if (c->keys[i]) {
+ EVP_PKEY_free(c->keys[i]);
+ c->keys[i] = NULL;
+ }
+ }
+ if (c->bio_is) {
+ SSL_BIO_close(c->bio_is);
+ c->bio_is = NULL;
+ }
+ if (c->bio_os) {
+ SSL_BIO_close(c->bio_os);
+ c->bio_os = NULL;
+ }
+ }
+ return APR_SUCCESS;
+}
+
+/* Initialize server context */
+TCN_IMPLEMENT_CALL(jlong, SSLContext, make)(TCN_STDARGS, jlong pool,
+ jint protocol, jint mode)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ tcn_ssl_ctxt_t *c = NULL;
+ SSL_CTX *ctx = NULL;
+ UNREFERENCED(o);
+
+ switch (protocol) {
+ case SSL_PROTOCOL_SSLV2:
+ case SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_TLSV1:
+ if (mode == SSL_MODE_CLIENT)
+ ctx = SSL_CTX_new(SSLv2_client_method());
+ else if (mode == SSL_MODE_SERVER)
+ ctx = SSL_CTX_new(SSLv2_server_method());
+ else
+ ctx = SSL_CTX_new(SSLv2_method());
+ break;
+ case SSL_PROTOCOL_SSLV3:
+ case SSL_PROTOCOL_SSLV3 | SSL_PROTOCOL_TLSV1:
+ if (mode == SSL_MODE_CLIENT)
+ ctx = SSL_CTX_new(SSLv3_client_method());
+ else if (mode == SSL_MODE_SERVER)
+ ctx = SSL_CTX_new(SSLv3_server_method());
+ else
+ ctx = SSL_CTX_new(SSLv3_method());
+ break;
+ case SSL_PROTOCOL_SSLV2 | SSL_PROTOCOL_SSLV3:
+ case SSL_PROTOCOL_ALL:
+ if (mode == SSL_MODE_CLIENT)
+ ctx = SSL_CTX_new(SSLv23_client_method());
+ else if (mode == SSL_MODE_SERVER)
+ ctx = SSL_CTX_new(SSLv23_server_method());
+ else
+ ctx = SSL_CTX_new(SSLv23_method());
+ break;
+ case SSL_PROTOCOL_TLSV1:
+ if (mode == SSL_MODE_CLIENT)
+ ctx = SSL_CTX_new(TLSv1_client_method());
+ else if (mode == SSL_MODE_SERVER)
+ ctx = SSL_CTX_new(TLSv1_server_method());
+ else
+ ctx = SSL_CTX_new(TLSv1_method());
+ break;
+ }
+ if (!ctx) {
+ tcn_ThrowException(e, "Invalid Server SSL Protocol");
+ goto init_failed;
+ }
+ if ((c = apr_pcalloc(p, sizeof(tcn_ssl_ctxt_t))) == NULL) {
+ tcn_ThrowAPRException(e, apr_get_os_error());
+ goto init_failed;
+ }
+
+ c->protocol = protocol;
+ c->mode = mode;
+ c->ctx = ctx;
+ c->pool = p;
+ c->bio_os = BIO_new(BIO_s_file());
+ if (c->bio_os != NULL)
+ BIO_set_fp(c->bio_os, stderr, BIO_NOCLOSE | BIO_FP_TEXT);
+ SSL_CTX_set_options(c->ctx, SSL_OP_ALL);
+ if (!(protocol & SSL_PROTOCOL_SSLV2))
+ SSL_CTX_set_options(c->ctx, SSL_OP_NO_SSLv2);
+ if (!(protocol & SSL_PROTOCOL_SSLV3))
+ SSL_CTX_set_options(c->ctx, SSL_OP_NO_SSLv3);
+ if (!(protocol & SSL_PROTOCOL_TLSV1))
+ SSL_CTX_set_options(c->ctx, SSL_OP_NO_TLSv1);
+ /*
+ * Configure additional context ingredients
+ */
+ SSL_CTX_set_options(c->ctx, SSL_OP_SINGLE_DH_USE);
+
+#ifdef SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION
+ /*
+ * Disallow a session from being resumed during a renegotiation,
+ * so that an acceptable cipher suite can be negotiated.
+ */
+ SSL_CTX_set_options(c->ctx, SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION);
+#endif
+ /* Default session context id and cache size */
+ SSL_CTX_sess_set_cache_size(c->ctx, SSL_DEFAULT_CACHE_SIZE);
+ MD5((const unsigned char *)SSL_DEFAULT_VHOST_NAME,
+ (unsigned long)(sizeof(SSL_DEFAULT_VHOST_NAME) - 1),
+ &(c->context_id[0]));
+ if (mode) {
+ SSL_CTX_set_tmp_rsa_callback(c->ctx, SSL_callback_tmp_RSA);
+ SSL_CTX_set_tmp_dh_callback(c->ctx, SSL_callback_tmp_DH);
+ }
+ /* Set default Certificate verification level
+ * and depth for the Client Authentication
+ */
+ c->verify_depth = 1;
+ c->verify_mode = SSL_CVERIFY_UNSET;
+ c->shutdown_type = SSL_SHUTDOWN_TYPE_UNSET;
+
+ /* Set default password callback */
+ SSL_CTX_set_default_passwd_cb(c->ctx, (pem_password_cb *)SSL_password_callback);
+ SSL_CTX_set_default_passwd_cb_userdata(c->ctx, (void *)(&tcn_password_callback));
+ /*
+ * Let us cleanup the ssl context when the pool is destroyed
+ */
+ apr_pool_cleanup_register(p, (const void *)c,
+ ssl_context_cleanup,
+ apr_pool_cleanup_null);
+
+ return P2J(c);
+init_failed:
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLContext, free)(TCN_STDARGS, jlong ctx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(ctx != 0);
+ /* Run and destroy the cleanup callback */
+ return apr_pool_cleanup_run(c->pool, c, ssl_context_cleanup);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setContextId)(TCN_STDARGS, jlong ctx,
+ jstring id)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ TCN_ALLOC_CSTRING(id);
+
+ TCN_ASSERT(ctx != 0);
+ UNREFERENCED(o);
+ if (J2S(id)) {
+ MD5((const unsigned char *)J2S(id),
+ (unsigned long)strlen(J2S(id)),
+ &(c->context_id[0]));
+ }
+ TCN_FREE_CSTRING(id);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setBIO)(TCN_STDARGS, jlong ctx,
+ jlong bio, jint dir)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ BIO *bio_handle = J2P(bio, BIO *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(ctx != 0);
+ if (dir == 0) {
+ if (c->bio_os && c->bio_os != bio_handle)
+ SSL_BIO_close(c->bio_os);
+ c->bio_os = bio_handle;
+ }
+ else if (dir == 1) {
+ if (c->bio_is && c->bio_is != bio_handle)
+ SSL_BIO_close(c->bio_is);
+ c->bio_is = bio_handle;
+ }
+ else
+ return;
+ SSL_BIO_doref(bio_handle);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setOptions)(TCN_STDARGS, jlong ctx,
+ jint opt)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(ctx != 0);
+ SSL_CTX_set_options(c->ctx, opt);
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setQuietShutdown)(TCN_STDARGS, jlong ctx,
+ jboolean mode)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(ctx != 0);
+ SSL_CTX_set_quiet_shutdown(c->ctx, mode ? 1 : 0);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCipherSuite)(TCN_STDARGS, jlong ctx,
+ jstring ciphers)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ TCN_ALLOC_CSTRING(ciphers);
+ jboolean rv = JNI_TRUE;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ if (!J2S(ciphers))
+ return JNI_FALSE;
+
+ if (!SSL_CTX_set_cipher_list(c->ctx, J2S(ciphers))) {
+ char err[256];
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Unable to configure permitted SSL ciphers (%s)", err);
+ rv = JNI_FALSE;
+ }
+ TCN_FREE_CSTRING(ciphers);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCARevocation)(TCN_STDARGS, jlong ctx,
+ jstring file,
+ jstring path)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ TCN_ALLOC_CSTRING(file);
+ TCN_ALLOC_CSTRING(path);
+ jboolean rv = JNI_FALSE;
+ X509_LOOKUP *lookup;
+ char err[256];
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ if (J2S(file) == NULL && J2S(path) == NULL)
+ return JNI_FALSE;
+
+ if (!c->crl) {
+ if ((c->crl = X509_STORE_new()) == NULL)
+ goto cleanup;
+ }
+ if (J2S(file)) {
+ lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_file());
+ if (lookup == NULL) {
+ ERR_error_string(ERR_get_error(), err);
+ X509_STORE_free(c->crl);
+ c->crl = NULL;
+ tcn_Throw(e, "Lookup failed for file %s (%s)", J2S(file), err);
+ goto cleanup;
+ }
+ X509_LOOKUP_load_file(lookup, J2S(file), X509_FILETYPE_PEM);
+ }
+ if (J2S(path)) {
+ lookup = X509_STORE_add_lookup(c->crl, X509_LOOKUP_hash_dir());
+ if (lookup == NULL) {
+ ERR_error_string(ERR_get_error(), err);
+ X509_STORE_free(c->crl);
+ c->crl = NULL;
+ tcn_Throw(e, "Lookup failed for path %s (%s)", J2S(file), err);
+ goto cleanup;
+ }
+ X509_LOOKUP_add_dir(lookup, J2S(path), X509_FILETYPE_PEM);
+ }
+ rv = JNI_TRUE;
+cleanup:
+ TCN_FREE_CSTRING(file);
+ TCN_FREE_CSTRING(path);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificateChainFile)(TCN_STDARGS, jlong ctx,
+ jstring file,
+ jboolean skipfirst)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jboolean rv = JNI_FALSE;
+ TCN_ALLOC_CSTRING(file);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ if (!J2S(file))
+ return JNI_FALSE;
+ if (SSL_CTX_use_certificate_chain(c->ctx, J2S(file), skipfirst) > 0)
+ rv = JNI_TRUE;
+ TCN_FREE_CSTRING(file);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCACertificate)(TCN_STDARGS,
+ jlong ctx,
+ jstring file,
+ jstring path)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jboolean rv = JNI_TRUE;
+ TCN_ALLOC_CSTRING(file);
+ TCN_ALLOC_CSTRING(path);
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ if (file == NULL && path == NULL)
+ return JNI_FALSE;
+
+ /*
+ * Configure Client Authentication details
+ */
+ if (!SSL_CTX_load_verify_locations(c->ctx,
+ J2S(file), J2S(path))) {
+ char err[256];
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Unable to configure locations "
+ "for client authentication (%s)", err);
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+ c->store = SSL_CTX_get_cert_store(c->ctx);
+ if (c->mode) {
+ STACK_OF(X509_NAME) *ca_certs;
+ c->ca_certs++;
+ ca_certs = SSL_CTX_get_client_CA_list(c->ctx);
+ if (ca_certs == NULL) {
+ SSL_load_client_CA_file(J2S(file));
+ if (ca_certs != NULL)
+ SSL_CTX_set_client_CA_list(c->ctx, (STACK *)ca_certs);
+ }
+ else {
+ if (!SSL_add_file_cert_subjects_to_stack((STACK *)ca_certs, J2S(file)))
+ ca_certs = NULL;
+ }
+ if (ca_certs == NULL && c->verify_mode == SSL_CVERIFY_REQUIRE) {
+ /*
+ * Give a warning when no CAs were configured but client authentication
+ * should take place. This cannot work.
+ */
+ BIO_printf(c->bio_os,
+ "[WARN] Oops, you want to request client "
+ "authentication, but no CAs are known for "
+ "verification!?");
+ }
+ }
+cleanup:
+ TCN_FREE_CSTRING(file);
+ TCN_FREE_CSTRING(path);
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setShutdownType)(TCN_STDARGS, jlong ctx,
+ jint type)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(ctx != 0);
+ c->shutdown_type = type;
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setVerify)(TCN_STDARGS, jlong ctx,
+ jint level, jint depth)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ int verify = SSL_VERIFY_NONE;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ c->verify_mode = level;
+
+ if (c->verify_mode == SSL_CVERIFY_UNSET)
+ c->verify_mode = SSL_CVERIFY_NONE;
+ if (depth > 0)
+ c->verify_depth = depth;
+ /*
+ * Configure callbacks for SSL context
+ */
+ if (c->verify_mode == SSL_CVERIFY_REQUIRE)
+ verify |= SSL_VERIFY_PEER_STRICT;
+ if ((c->verify_mode == SSL_CVERIFY_OPTIONAL) ||
+ (c->verify_mode == SSL_CVERIFY_OPTIONAL_NO_CA))
+ verify |= SSL_VERIFY_PEER;
+ if (!c->store) {
+ if (SSL_CTX_set_default_verify_paths(c->ctx)) {
+ c->store = SSL_CTX_get_cert_store(c->ctx);
+ X509_STORE_set_flags(c->store, 0);
+ }
+ else {
+ /* XXX: See if this is fatal */
+ }
+ }
+
+ SSL_CTX_set_verify(c->ctx, verify, SSL_callback_SSL_verify);
+}
+
+static EVP_PKEY *load_pem_key(tcn_ssl_ctxt_t *c, const char *file)
+{
+ BIO *bio = NULL;
+ EVP_PKEY *key = NULL;
+ void *cb_data = c->cb_data;
+
+ if ((bio = BIO_new(BIO_s_file())) == NULL) {
+ return NULL;
+ }
+ if (BIO_read_filename(bio, file) <= 0) {
+ BIO_free(bio);
+ return NULL;
+ }
+ if (!cb_data)
+ cb_data = &tcn_password_callback;
+ key = PEM_read_bio_PrivateKey(bio, NULL,
+ (pem_password_cb *)SSL_password_callback,
+ cb_data);
+ BIO_free(bio);
+ return key;
+}
+
+static X509 *load_pem_cert(const char *file)
+{
+ BIO *bio = NULL;
+ X509 *cert = NULL;
+
+ if ((bio = BIO_new(BIO_s_file())) == NULL) {
+ return NULL;
+ }
+ if (BIO_read_filename(bio, file) <= 0) {
+ BIO_free(bio);
+ return NULL;
+ }
+ cert = PEM_read_bio_X509_AUX(bio, NULL,
+ (pem_password_cb *)SSL_password_callback,
+ NULL);
+ BIO_free(bio);
+ return cert;
+}
+
+TCN_IMPLEMENT_CALL(void, SSLContext, setRandom)(TCN_STDARGS, jlong ctx,
+ jstring file)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ TCN_ALLOC_CSTRING(file);
+
+ TCN_ASSERT(ctx != 0);
+ UNREFERENCED(o);
+ if (J2S(file))
+ c->rand_file = apr_pstrdup(c->pool, J2S(file));
+ TCN_FREE_CSTRING(file);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, SSLContext, setCertificate)(TCN_STDARGS, jlong ctx,
+ jstring cert, jstring key,
+ jstring password, jint idx)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ jboolean rv = JNI_TRUE;
+ TCN_ALLOC_CSTRING(cert);
+ TCN_ALLOC_CSTRING(key);
+ TCN_ALLOC_CSTRING(password);
+ const char *key_file, *cert_file;
+ char err[256];
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+
+ if (idx < 0 || idx >= SSL_AIDX_MAX) {
+ /* TODO: Throw something */
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+ if (J2S(password)) {
+ if (!c->cb_data)
+ c->cb_data = &tcn_password_callback;
+ strncpy(c->cb_data->password, J2S(password), SSL_MAX_PASSWORD_LEN);
+ c->cb_data->password[SSL_MAX_PASSWORD_LEN-1] = '\0';
+ }
+ key_file = J2S(key);
+ cert_file = J2S(cert);
+ if (!key_file)
+ key_file = cert_file;
+ if (!key_file) {
+ tcn_Throw(e, "No Certificate file specified");
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+ if ((c->keys[idx] = load_pem_key(c, key_file)) == NULL) {
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Unable to load certificate key %s (%s)",
+ key_file, err);
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+ if ((c->certs[idx] = load_pem_cert(cert_file)) == NULL) {
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Unable to load certificate %s (%s)",
+ cert_file, err);
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+ if (SSL_CTX_use_certificate(c->ctx, c->certs[idx]) <= 0) {
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Error setting certificate (%s)", err);
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+ if (SSL_CTX_use_PrivateKey(c->ctx, c->keys[idx]) <= 0) {
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Error setting private key (%s)", err);
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+ if (SSL_CTX_check_private_key(c->ctx) <= 0) {
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(e, "Private key does not match the certificate public key (%s)",
+ err);
+ rv = JNI_FALSE;
+ goto cleanup;
+ }
+cleanup:
+ TCN_FREE_CSTRING(cert);
+ TCN_FREE_CSTRING(key);
+ TCN_FREE_CSTRING(password);
+ return rv;
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL info wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision$, $Date$
+ */
+
+#include "tcn.h"
+#include "apr_file_io.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+static const char *hex_basis = "0123456789ABCDEF";
+
+static char *convert_to_hex(const void *buf, size_t len)
+{
+ const unsigned char *p = ( const unsigned char *)buf;
+ char *str, *s;
+ size_t i;
+
+ if ((len < 1) || ((str = malloc(len * 2 + 1)) == NULL))
+ return NULL;
+ for (i = 0, s = str; i < len; i++) {
+ unsigned char c = *p++;
+ *s++ = hex_basis[c >> 4];
+ *s++ = hex_basis[c & 0x0F];
+ }
+ *s = '\0';
+ return str;
+}
+
+#define DIGIT2NUM(x) (((x)[0] - '0') * 10 + (x)[1] - '0')
+
+static int get_days_remaining(ASN1_UTCTIME *tm)
+{
+ apr_time_t then, now = apr_time_now();
+ apr_time_exp_t exp = {0};
+ int diff;
+
+ /* Fail if the time isn't a valid ASN.1 UTCTIME; RFC3280 mandates
+ * that the seconds digits are present even though ASN.1
+ * doesn't. */
+ if (tm->length < 11 || !ASN1_UTCTIME_check(tm))
+ return 0;
+
+ exp.tm_year = DIGIT2NUM(tm->data);
+ exp.tm_mon = DIGIT2NUM(tm->data + 2) - 1;
+ exp.tm_mday = DIGIT2NUM(tm->data + 4) + 1;
+ exp.tm_hour = DIGIT2NUM(tm->data + 6);
+ exp.tm_min = DIGIT2NUM(tm->data + 8);
+ exp.tm_sec = DIGIT2NUM(tm->data + 10);
+
+ if (exp.tm_year <= 50)
+ exp.tm_year += 100;
+ if (apr_time_exp_gmt_get(&then, &exp) != APR_SUCCESS)
+ return 0;
+
+ diff = (int)((apr_time_sec(then) - apr_time_sec(now)) / (60*60*24));
+ return diff > 0 ? diff : 0;
+}
+
+static char *get_cert_valid(ASN1_UTCTIME *tm)
+{
+ char *result;
+ BIO* bio;
+ int n;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return NULL;
+ ASN1_UTCTIME_print(bio, tm);
+ n = BIO_pending(bio);
+ result = malloc(n+1);
+ n = BIO_read(bio, result, n);
+ result[n] = '\0';
+ BIO_free(bio);
+ return result;
+}
+
+static char *get_cert_PEM(X509 *xs)
+{
+ char *result = NULL;
+ BIO *bio;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return NULL;
+ if (PEM_write_bio_X509(bio, xs)) {
+ int n = BIO_pending(bio);
+ result = malloc(n+1);
+ n = BIO_read(bio, result, n);
+ result[n] = '\0';
+ }
+ BIO_free(bio);
+ return result;
+}
+
+static unsigned char *get_cert_ASN1(X509 *xs, int *len)
+{
+ unsigned char *result = NULL;
+ BIO *bio;
+
+ *len = 0;
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return NULL;
+ if (i2d_X509_bio(bio, xs)) {
+ int n = BIO_pending(bio);
+ result = malloc(n);
+ n = BIO_read(bio, result, n);
+ *len = n;
+ }
+ BIO_free(bio);
+ return result;
+}
+
+
+static char *get_cert_serial(X509 *xs)
+{
+ char *result;
+ BIO *bio;
+ int n;
+
+ if ((bio = BIO_new(BIO_s_mem())) == NULL)
+ return NULL;
+ i2a_ASN1_INTEGER(bio, X509_get_serialNumber(xs));
+ n = BIO_pending(bio);
+ result = malloc(n+1);
+ n = BIO_read(bio, result, n);
+ result[n] = '\0';
+ BIO_free(bio);
+ return result;
+}
+
+static const struct {
+ int fid;
+ int nid;
+} info_cert_dn_rec[] = {
+ { SSL_INFO_DN_COUNTRYNAME, NID_countryName },
+ { SSL_INFO_DN_STATEORPROVINCENAME, NID_stateOrProvinceName },
+ { SSL_INFO_DN_LOCALITYNAME, NID_localityName },
+ { SSL_INFO_DN_ORGANIZATIONNAME, NID_organizationName },
+ { SSL_INFO_DN_ORGANIZATIONALUNITNAME, NID_organizationalUnitName },
+ { SSL_INFO_DN_COMMONNAME, NID_commonName },
+ { SSL_INFO_DN_TITLE, NID_title },
+ { SSL_INFO_DN_INITIALS, NID_initials },
+ { SSL_INFO_DN_GIVENNAME, NID_givenName },
+ { SSL_INFO_DN_SURNAME, NID_surname },
+ { SSL_INFO_DN_DESCRIPTION, NID_description },
+ { SSL_INFO_DN_UNIQUEIDENTIFIER, NID_x500UniqueIdentifier },
+ { SSL_INFO_DN_EMAILADDRESS, NID_pkcs9_emailAddress },
+ { 0, 0 }
+};
+
+static char *lookup_ssl_cert_dn(X509_NAME *xsname, int dnidx)
+{
+ char *result;
+ X509_NAME_ENTRY *xsne;
+ int i, j, n, idx = 0;
+
+ result = NULL;
+
+ for (i = 0; info_cert_dn_rec[i].fid != 0; i++) {
+ if (info_cert_dn_rec[i].fid == dnidx) {
+ for (j = 0; j < sk_X509_NAME_ENTRY_num((STACK_OF(X509_NAME_ENTRY) *)
+ (xsname->entries)); j++) {
+ xsne = sk_X509_NAME_ENTRY_value((STACK_OF(X509_NAME_ENTRY) *)
+ (xsname->entries), j);
+
+ n =OBJ_obj2nid((ASN1_OBJECT *)X509_NAME_ENTRY_get_object(xsne));
+ if (n == info_cert_dn_rec[i].nid && idx-- == 0) {
+ result = malloc(xsne->value->length + 1);
+ memcpy(result, xsne->value->data,
+ xsne->value->length);
+ result[xsne->value->length] = '\0';
+
+#if APR_CHARSET_EBCDIC
+ ap_xlate_proto_from_ascii(result, xsne->value->length);
+#endif /* APR_CHARSET_EBCDIC */
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return result;
+}
+
+TCN_IMPLEMENT_CALL(jobject, SSLSocket, getInfoB)(TCN_STDARGS, jlong sock,
+ jint what)
+{
+ tcn_socket_t *a = J2P(sock, tcn_socket_t *);
+ tcn_ssl_conn_t *s;
+ jbyteArray array = NULL;
+ apr_status_t rv = APR_SUCCESS;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ s = (tcn_ssl_conn_t *)(a->opaque);
+ switch (what) {
+ case SSL_INFO_SESSION_ID:
+ {
+ SSL_SESSION *session = SSL_get_session(s->ssl);
+ if (session) {
+ array = tcn_new_arrayb(e, &session->session_id[0],
+ session->session_id_length);
+ }
+ }
+ break;
+ default:
+ rv = APR_EINVAL;
+ break;
+ }
+ if (what & SSL_INFO_CLIENT_MASK) {
+ X509 *xs;
+ unsigned char *result;
+ int len;
+ if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+ switch (what) {
+ case SSL_INFO_CLIENT_CERT:
+ if ((result = get_cert_ASN1(xs, &len))) {
+ array = tcn_new_arrayb(e, result, len);
+ free(result);
+ }
+ break;
+ }
+ X509_free(xs);
+ }
+ rv = APR_SUCCESS;
+ }
+ else if (what & SSL_INFO_SERVER_MASK) {
+ X509 *xs;
+ unsigned char *result;
+ int len;
+ if ((xs = SSL_get_certificate(s->ssl)) != NULL) {
+ switch (what) {
+ case SSL_INFO_SERVER_CERT:
+ if ((result = get_cert_ASN1(xs, &len))) {
+ array = tcn_new_arrayb(e, result, len);
+ free(result);
+ }
+ break;
+ }
+ /* XXX: No need to call the X509_free(xs); */
+ }
+ rv = APR_SUCCESS;
+ }
+ else if (what & SSL_INFO_CLIENT_CERT_CHAIN) {
+ X509 *xs;
+ unsigned char *result;
+ STACK_OF(X509) *sk = SSL_get_peer_cert_chain(s->ssl);
+ int len, n = what & 0x0F;
+ if (n < sk_X509_num(sk)) {
+ xs = sk_X509_value(sk, n);
+ if ((result = get_cert_ASN1(xs, &len))) {
+ array = tcn_new_arrayb(e, result, len);
+ free(result);
+ }
+ }
+ rv = APR_SUCCESS;
+ }
+ if (rv != APR_SUCCESS)
+ tcn_ThrowAPRException(e, rv);
+
+ return array;
+}
+
+TCN_IMPLEMENT_CALL(jstring, SSLSocket, getInfoS)(TCN_STDARGS, jlong sock,
+ jint what)
+{
+ tcn_socket_t *a = J2P(sock, tcn_socket_t *);
+ tcn_ssl_conn_t *s;
+ jstring value = NULL;
+ apr_status_t rv = APR_SUCCESS;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ s = (tcn_ssl_conn_t *)(a->opaque);
+ switch (what) {
+ case SSL_INFO_SESSION_ID:
+ {
+ SSL_SESSION *session = SSL_get_session(s->ssl);
+ if (session) {
+ char *hs = convert_to_hex(&session->session_id[0],
+ session->session_id_length);
+ if (hs) {
+ value = tcn_new_string(e, hs);
+ free(hs);
+ }
+ }
+ }
+ break;
+ case SSL_INFO_PROTOCOL:
+ value = tcn_new_string(e, SSL_get_version(s->ssl));
+ break;
+ case SSL_INFO_CIPHER:
+ value = tcn_new_string(e, SSL_get_cipher_name(s->ssl));
+ break;
+ case SSL_INFO_CIPHER_VERSION:
+ value = tcn_new_string(e, SSL_get_cipher_version(s->ssl));
+ break;
+ case SSL_INFO_CIPHER_DESCRIPTION:
+ {
+ SSL_CIPHER *cipher = SSL_get_current_cipher(s->ssl);
+ if (cipher) {
+ char buf[256];
+ char *desc = SSL_CIPHER_description(cipher, buf, 256);
+ value = tcn_new_string(e, desc);
+ }
+ }
+ break;
+ default:
+ rv = APR_EINVAL;
+ break;
+ }
+ if (what & (SSL_INFO_CLIENT_S_DN | SSL_INFO_CLIENT_I_DN)) {
+ X509 *xs;
+ X509_NAME *xsname;
+ if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+ char *result;
+ int idx = what & 0x0F;
+ if (what & SSL_INFO_CLIENT_S_DN)
+ xsname = X509_get_subject_name(xs);
+ else
+ xsname = X509_get_issuer_name(xs);
+ if (idx) {
+ result = lookup_ssl_cert_dn(xsname, idx);
+ if (result) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ }
+ else
+ value = tcn_new_string(e, X509_NAME_oneline(xsname, NULL, 0));
+ X509_free(xs);
+ }
+ rv = APR_SUCCESS;
+ }
+ else if (what & (SSL_INFO_SERVER_S_DN | SSL_INFO_SERVER_I_DN)) {
+ X509 *xs;
+ X509_NAME *xsname;
+ if ((xs = SSL_get_certificate(s->ssl)) != NULL) {
+ char *result;
+ int idx = what & 0x0F;
+ if (what & SSL_INFO_SERVER_S_DN)
+ xsname = X509_get_subject_name(xs);
+ else
+ xsname = X509_get_issuer_name(xs);
+ if (idx) {
+ result = lookup_ssl_cert_dn(xsname, what & 0x0F);
+ if (result) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ }
+ else
+ value = tcn_new_string(e, X509_NAME_oneline(xsname, NULL, 0));
+ /* XXX: No need to call the X509_free(xs); */
+ }
+ rv = APR_SUCCESS;
+ }
+ else if (what & SSL_INFO_CLIENT_MASK) {
+ X509 *xs;
+ char *result;
+ int nid;
+ if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+ switch (what) {
+ case SSL_INFO_CLIENT_V_START:
+ if ((result = get_cert_valid(X509_get_notBefore(xs)))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ case SSL_INFO_CLIENT_V_END:
+ if ((result = get_cert_valid(X509_get_notAfter(xs)))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ case SSL_INFO_CLIENT_A_SIG:
+ nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->signature->algorithm);
+ if (nid == NID_undef)
+ value = tcn_new_string(e, "UNKNOWN");
+ else
+ value = tcn_new_string(e, OBJ_nid2ln(nid));
+ break;
+ case SSL_INFO_CLIENT_A_KEY:
+ nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->key->algor->algorithm);
+ if (nid == NID_undef)
+ value = tcn_new_string(e, "UNKNOWN");
+ else
+ value = tcn_new_string(e, OBJ_nid2ln(nid));
+ break;
+ case SSL_INFO_CLIENT_CERT:
+ if ((result = get_cert_PEM(xs))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ case SSL_INFO_CLIENT_M_SERIAL:
+ if ((result = get_cert_serial(xs))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ }
+ X509_free(xs);
+ }
+ rv = APR_SUCCESS;
+ }
+ else if (what & SSL_INFO_SERVER_MASK) {
+ X509 *xs;
+ char *result;
+ int nid;
+ if ((xs = SSL_get_certificate(s->ssl)) != NULL) {
+ switch (what) {
+ case SSL_INFO_SERVER_V_START:
+ if ((result = get_cert_valid(X509_get_notBefore(xs)))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ case SSL_INFO_SERVER_V_END:
+ if ((result = get_cert_valid(X509_get_notAfter(xs)))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ case SSL_INFO_SERVER_A_SIG:
+ nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->signature->algorithm);
+ if (nid == NID_undef)
+ value = tcn_new_string(e, "UNKNOWN");
+ else
+ value = tcn_new_string(e, OBJ_nid2ln(nid));
+ break;
+ case SSL_INFO_SERVER_A_KEY:
+ nid = OBJ_obj2nid((ASN1_OBJECT *)xs->cert_info->key->algor->algorithm);
+ if (nid == NID_undef)
+ value = tcn_new_string(e, "UNKNOWN");
+ else
+ value = tcn_new_string(e, OBJ_nid2ln(nid));
+ break;
+ case SSL_INFO_SERVER_CERT:
+ if ((result = get_cert_PEM(xs))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ case SSL_INFO_SERVER_M_SERIAL:
+ if ((result = get_cert_serial(xs))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ break;
+ }
+ /* XXX: No need to call the X509_free(xs); */
+ }
+ rv = APR_SUCCESS;
+ }
+ else if (what & SSL_INFO_CLIENT_CERT_CHAIN) {
+ X509 *xs;
+ char *result;
+ STACK_OF(X509) *sk = SSL_get_peer_cert_chain(s->ssl);
+ int n = what & 0x0F;
+ if (n < sk_X509_num(sk)) {
+ xs = sk_X509_value(sk, n);
+ if ((result = get_cert_PEM(xs))) {
+ value = tcn_new_string(e, result);
+ free(result);
+ }
+ }
+ rv = APR_SUCCESS;
+ }
+ if (rv != APR_SUCCESS)
+ tcn_ThrowAPRException(e, rv);
+
+ return value;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, getInfoI)(TCN_STDARGS, jlong sock,
+ jint what)
+{
+ tcn_socket_t *a = J2P(sock, tcn_socket_t *);
+ tcn_ssl_conn_t *s;
+ apr_status_t rv = APR_SUCCESS;
+ jint value = -1;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(sock != 0);
+
+ s = (tcn_ssl_conn_t *)(a->opaque);
+
+ switch (what) {
+ case SSL_INFO_CIPHER_USEKEYSIZE:
+ case SSL_INFO_CIPHER_ALGKEYSIZE:
+ {
+ int usekeysize = 0;
+ int algkeysize = 0;
+ SSL_CIPHER *cipher = SSL_get_current_cipher(s->ssl);
+ if (cipher) {
+ usekeysize = SSL_CIPHER_get_bits(cipher, &algkeysize);
+ if (what == SSL_INFO_CIPHER_USEKEYSIZE)
+ value = usekeysize;
+ else
+ value = algkeysize;
+ }
+ }
+ break;
+ case SSL_INFO_CLIENT_CERT_CHAIN:
+ {
+ STACK_OF(X509) *sk = SSL_get_peer_cert_chain(s->ssl);
+ value = sk_X509_num(sk);
+ }
+ break;
+ default:
+ rv = APR_EINVAL;
+ break;
+ }
+ if (what & SSL_INFO_CLIENT_MASK) {
+ X509 *xs;
+ if ((xs = SSL_get_peer_certificate(s->ssl)) != NULL) {
+ switch (what) {
+ case SSL_INFO_CLIENT_V_REMAIN:
+ value = get_days_remaining(X509_get_notAfter(xs));
+ rv = APR_SUCCESS;
+ break;
+ default:
+ rv = APR_EINVAL;
+ break;
+ }
+ X509_free(xs);
+ }
+ }
+
+ if (rv != APR_SUCCESS)
+ tcn_ThrowAPRException(e, rv);
+ return value;
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL network wrapper
+ *
+ * @author Mladen Turk
+ * @version $Revision$, $Date$
+ */
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t ssl_created = 0;
+static volatile apr_uint32_t ssl_closed = 0;
+static volatile apr_uint32_t ssl_cleared = 0;
+static volatile apr_uint32_t ssl_accepted = 0;
+
+void ssl_network_dump_statistics()
+{
+ fprintf(stderr, "SSL Network Statistics ..\n");
+ fprintf(stderr, "Sockets created : %d\n", ssl_created);
+ fprintf(stderr, "Sockets accepted : %d\n", ssl_accepted);
+ fprintf(stderr, "Sockets closed : %d\n", ssl_closed);
+ fprintf(stderr, "Sockets cleared : %d\n", ssl_cleared);
+}
+
+#endif
+
+static int ssl_smart_shutdown(SSL *ssl, int shutdown_type)
+{
+ int i;
+ int rc = 0;
+
+ switch (shutdown_type) {
+ case SSL_SHUTDOWN_TYPE_UNCLEAN:
+ /* perform no close notify handshake at all
+ * (violates the SSL/TLS standard!)
+ */
+ shutdown_type = SSL_SENT_SHUTDOWN|SSL_RECEIVED_SHUTDOWN;
+ break;
+ case SSL_SHUTDOWN_TYPE_ACCURATE:
+ /* send close notify and wait for clients close notify
+ * (standard compliant, but usually causes connection hangs)
+ */
+ shutdown_type = 0;
+ break;
+ default:
+ /*
+ * case SSL_SHUTDOWN_TYPE_UNSET:
+ * case SSL_SHUTDOWN_TYPE_STANDARD:
+ * send close notify, but don't wait for clients close notify
+ * (standard compliant and safe, so it's the DEFAULT!)
+ */
+ shutdown_type = SSL_RECEIVED_SHUTDOWN;
+ break;
+ }
+
+ SSL_set_shutdown(ssl, shutdown_type);
+ /*
+ * Repeat the calls, because SSL_shutdown internally dispatches through a
+ * little state machine. Usually only one or two interation should be
+ * needed, so we restrict the total number of restrictions in order to
+ * avoid process hangs in case the client played bad with the socket
+ * connection and OpenSSL cannot recognize it.
+ * max 2x pending + 2x data = 4
+ */
+ for (i = 0; i < 4; i++) {
+ if ((rc = SSL_shutdown(ssl)))
+ break;
+ }
+ return rc;
+}
+
+static apr_status_t ssl_cleanup(void *data)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)data;
+
+ if (con) {
+ if (con->ssl) {
+ ssl_smart_shutdown(con->ssl, con->shutdown_type);
+ SSL_free(con->ssl);
+ con->ssl = NULL;
+ }
+ if (con->peer) {
+ X509_free(con->peer);
+ con->peer = NULL;
+ }
+ }
+
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&ssl_cleared);
+#endif
+ return APR_SUCCESS;
+}
+
+static tcn_ssl_conn_t *ssl_create(JNIEnv *env, tcn_ssl_ctxt_t *ctx, apr_pool_t *pool)
+{
+ tcn_ssl_conn_t *con;
+ SSL *ssl;
+
+ if ((con = apr_pcalloc(pool, sizeof(tcn_ssl_conn_t))) == NULL) {
+ tcn_ThrowAPRException(env, apr_get_os_error());
+ return NULL;
+ }
+ if ((ssl = SSL_new(ctx->ctx)) == NULL) {
+ char err[256];
+ ERR_error_string(ERR_get_error(), err);
+ tcn_Throw(env, "SSL_new failed (%s)", err);
+ con = NULL;
+ return NULL;
+ }
+ SSL_clear(ssl);
+ con->pool = pool;
+ con->ctx = ctx;
+ con->ssl = ssl;
+ con->shutdown_type = ctx->shutdown_type;
+ apr_pollset_create(&(con->pollset), 1, pool, 0);
+
+ SSL_set_app_data(ssl, (void *)con);
+
+ if (ctx->mode) {
+ /*
+ * Configure callbacks for SSL connection
+ */
+ SSL_set_tmp_rsa_callback(ssl, SSL_callback_tmp_RSA);
+ SSL_set_tmp_dh_callback(ssl, SSL_callback_tmp_DH);
+ SSL_set_session_id_context(ssl, &(ctx->context_id[0]),
+ MD5_DIGEST_LENGTH);
+ }
+ SSL_set_verify_result(ssl, X509_V_OK);
+ SSL_rand_seed(ctx->rand_file);
+
+#ifdef TCN_DO_STATISTICS
+ ssl_created++;
+#endif
+ return con;
+}
+
+static apr_status_t wait_for_io_or_timeout(tcn_ssl_conn_t *con,
+ int for_what)
+{
+ apr_interval_time_t timeout;
+ apr_pollfd_t pfd;
+ int type;
+ apr_status_t status;
+
+ /* Figure out the the poll direction */
+ switch (for_what) {
+ case SSL_ERROR_WANT_WRITE:
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ type = APR_POLLOUT;
+ break;
+ case SSL_ERROR_WANT_READ:
+ type = APR_POLLIN;
+ break;
+ default:
+ return APR_EINVAL;
+ break;
+ }
+
+ apr_socket_timeout_get(con->sock, &timeout);
+ pfd.desc_type = APR_POLL_SOCKET;
+ pfd.desc.s = con->sock;
+ pfd.reqevents = type;
+
+ /* Remove the object if it was in the pollset, then add in the new
+ * object with the correct reqevents value. Ignore the status result
+ * on the remove, because it might not be in there (yet).
+ */
+ apr_pollset_remove(con->pollset, &pfd);
+
+ /* ### check status code */
+ apr_pollset_add(con->pollset, &pfd);
+
+ do {
+ int numdesc;
+ const apr_pollfd_t *pdesc;
+
+ status = apr_pollset_poll(con->pollset, timeout, &numdesc, &pdesc);
+ if (numdesc == 1 && (pdesc[0].rtnevents & type) != 0)
+ return APR_SUCCESS;
+ } while (APR_STATUS_IS_EINTR(status));
+
+ return status;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ return apr_socket_timeout_set(con->sock, t);
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ return apr_socket_timeout_get(con->sock, t);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ssl_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ return apr_socket_opt_set(con->sock, opt, on);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ssl_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ return apr_socket_opt_get(con->sock, opt, on);
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+ apr_status_t rv = APR_SUCCESS;
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+
+ if (con->ssl) {
+ if (how < 1)
+ how = con->shutdown_type;
+ rv = ssl_smart_shutdown(con->ssl, how);
+ /* TODO: Translate OpenSSL Error codes */
+ SSL_free(con->ssl);
+ con->ssl = NULL;
+ }
+ return rv;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_close(apr_socket_t *sock)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ apr_status_t rv = APR_SUCCESS;
+
+#ifdef TCN_DO_STATISTICS
+ apr_atomic_inc32(&ssl_closed);
+#endif
+ if (con->ssl) {
+ rv = ssl_smart_shutdown(con->ssl, con->shutdown_type);
+ SSL_free(con->ssl);
+ con->ssl = NULL;
+ }
+ if (con->peer) {
+ X509_free(con->peer);
+ con->peer = NULL;
+ }
+ return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, handshake)(TCN_STDARGS, jlong sock)
+{
+ tcn_socket_t *ss = J2P(sock, tcn_socket_t *);
+ tcn_ssl_conn_t *con;
+ int s;
+ apr_status_t rv;
+ X509 *peer;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ if (ss->net->type != TCN_SOCKET_SSL)
+ return APR_EINVAL;
+ con = (tcn_ssl_conn_t *)ss->opaque;
+ while (!SSL_is_init_finished(con->ssl)) {
+ if ((s = SSL_do_handshake(con->ssl)) <= 0) {
+ int i = SSL_get_error(con->ssl, s);
+ switch (i) {
+ case SSL_ERROR_NONE:
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+ return APR_SUCCESS;
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return rv;
+ }
+ break;
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ s = apr_get_netos_error();
+ if (!APR_STATUS_IS_EAGAIN(s) &&
+ !APR_STATUS_IS_EINTR(s)) {
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return s;
+ }
+ break;
+ default:
+ /*
+ * Anything else is a fatal error
+ */
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return SSL_TO_APR_ERROR(i);
+ break;
+ }
+ }
+ /*
+ * Check for failed client authentication
+ */
+ if (SSL_get_verify_result(con->ssl) != X509_V_OK) {
+ /* TODO: Log SSL client authentication failed */
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ /* TODO: Figure out the correct return value */
+ return APR_EGENERAL;
+ }
+
+ /*
+ * Remember the peer certificate
+ */
+ if ((peer = SSL_get_peer_certificate(con->ssl)) != NULL) {
+ if (con->peer)
+ X509_free(con->peer);
+ con->peer = peer;
+ }
+ }
+ return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ int s, wr = (int)(*len);
+ apr_status_t rv = APR_SUCCESS;
+
+ for (;;) {
+ if ((s = SSL_read(con->ssl, buf, wr)) <= 0) {
+ apr_status_t os = apr_get_netos_error();
+ int i = SSL_get_error(con->ssl, s);
+ /* Special case if the "close notify" alert send by peer */
+ if (s == 0 && (con->ssl->shutdown & SSL_RECEIVED_SHUTDOWN)) {
+ *len = 0;
+ return APR_EOF;
+ }
+ switch (i) {
+ case SSL_ERROR_ZERO_RETURN:
+ *len = 0;
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+ return APR_EOF;
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return rv;
+ }
+ break;
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ if (!APR_STATUS_IS_EAGAIN(os) &&
+ !APR_STATUS_IS_EINTR(os)) {
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return os;
+ }
+ break;
+ default:
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return os;
+ break;
+ }
+ }
+ else {
+ *len = s;
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+ break;
+ }
+ }
+ return rv;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_send(apr_socket_t *sock, const char *buf,
+ apr_size_t *len)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ int s, wr = (int)(*len);
+ apr_status_t rv = APR_SUCCESS;
+
+ for (;;) {
+ if ((s = SSL_write(con->ssl, buf, wr)) <= 0) {
+ apr_status_t os = apr_get_netos_error();
+ int i = SSL_get_error(con->ssl, s);
+ switch (i) {
+ case SSL_ERROR_ZERO_RETURN:
+ *len = 0;
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_STANDARD;
+ return APR_EOF;
+ break;
+ case SSL_ERROR_WANT_READ:
+ case SSL_ERROR_WANT_WRITE:
+ if ((rv = wait_for_io_or_timeout(con, i)) != APR_SUCCESS) {
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return rv;
+ }
+ break;
+ case SSL_ERROR_SYSCALL:
+ case SSL_ERROR_SSL:
+ if (!APR_STATUS_IS_EAGAIN(os) &&
+ !APR_STATUS_IS_EINTR(os)) {
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return os;
+ }
+ break;
+ default:
+ con->shutdown_type = SSL_SHUTDOWN_TYPE_UNCLEAN;
+ return os;
+ break;
+ }
+ }
+ else {
+ *len = s;
+ break;
+ }
+ }
+ return rv;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ssl_socket_sendv(apr_socket_t *sock,
+ const struct iovec *vec,
+ apr_int32_t nvec, apr_size_t *len)
+{
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)sock;
+ apr_status_t rv;
+ apr_size_t written = 0;
+ apr_int32_t i;
+
+ for (i = 0; i < nvec; i++) {
+ apr_size_t rd = vec[i].iov_len;
+ if ((rv = ssl_socket_send((apr_socket_t *)con,
+ vec[i].iov_base, &rd)) != APR_SUCCESS) {
+ *len = written;
+ return rv;
+ }
+ written += rd;
+ }
+ *len = written;
+ return APR_SUCCESS;
+}
+
+static tcn_nlayer_t ssl_socket_layer = {
+ TCN_SOCKET_SSL,
+ ssl_cleanup,
+ ssl_socket_close,
+ ssl_socket_shutdown,
+ ssl_socket_opt_get,
+ ssl_socket_opt_set,
+ ssl_socket_timeout_get,
+ ssl_socket_timeout_set,
+ ssl_socket_send,
+ ssl_socket_sendv,
+ ssl_socket_recv
+};
+
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, attach)(TCN_STDARGS, jlong ctx,
+ jlong sock)
+{
+ tcn_ssl_ctxt_t *c = J2P(ctx, tcn_ssl_ctxt_t *);
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ tcn_ssl_conn_t *con;
+ apr_os_sock_t oss;
+ apr_status_t rv;
+
+ UNREFERENCED(o);
+ TCN_ASSERT(ctx != 0);
+ TCN_ASSERT(sock != 0);
+
+ if ((rv = apr_os_sock_get(&oss, s->sock)) != APR_SUCCESS)
+ return rv;
+ if ((con = ssl_create(e, c, s->pool)) == NULL)
+ return APR_EGENERAL;
+ con->sock = s->sock;
+
+ SSL_set_fd(con->ssl, (int)oss);
+ if (c->mode)
+ SSL_set_accept_state(con->ssl);
+ else
+ SSL_set_connect_state(con->ssl);
+ /* Change socket type */
+ s->net = &ssl_socket_layer;
+ s->opaque = con;
+
+ return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jint, SSLSocket, renegotiate)(TCN_STDARGS,
+ jlong sock)
+{
+ tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+ tcn_ssl_conn_t *con;
+
+ UNREFERENCED_STDARGS;
+ TCN_ASSERT(sock != 0);
+ con = (tcn_ssl_conn_t *)s->opaque;
+ return SSL_renegotiate(con->ssl);
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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.
+ */
+
+/** SSL Utilities
+ *
+ * @author Mladen Turk
+ * @version $Revision$, $Date$
+ */
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef HAVE_OPENSSL
+#include "ssl_private.h"
+
+#ifdef WIN32
+extern int WIN32_SSL_password_prompt(tcn_pass_cb_t *data);
+#endif
+
+/* _________________________________________________________________
+**
+** Additional High-Level Functions for OpenSSL
+** _________________________________________________________________
+*/
+
+/* we initialize this index at startup time
+ * and never write to it at request time,
+ * so this static is thread safe.
+ * also note that OpenSSL increments at static variable when
+ * SSL_get_ex_new_index() is called, so we _must_ do this at startup.
+ */
+static int SSL_app_data2_idx = -1;
+
+void SSL_init_app_data2_idx(void)
+{
+ int i;
+
+ if (SSL_app_data2_idx > -1) {
+ return;
+ }
+
+ /* we _do_ need to call this twice */
+ for (i = 0; i <= 1; i++) {
+ SSL_app_data2_idx =
+ SSL_get_ex_new_index(0,
+ "Second Application Data for SSL",
+ NULL, NULL, NULL);
+ }
+}
+
+void *SSL_get_app_data2(SSL *ssl)
+{
+ return (void *)SSL_get_ex_data(ssl, SSL_app_data2_idx);
+}
+
+void SSL_set_app_data2(SSL *ssl, void *arg)
+{
+ SSL_set_ex_data(ssl, SSL_app_data2_idx, (char *)arg);
+ return;
+}
+
+/* Simple echo password prompting */
+int SSL_password_prompt(tcn_pass_cb_t *data)
+{
+ int rv = 0;
+ data->password[0] = '\0';
+ if (data->cb.obj) {
+ JNIEnv *e;
+ jobject o;
+ jstring prompt = AJP_TO_JSTRING(data->prompt);
+ tcn_get_java_env(&e);
+ if ((o = (*e)->CallObjectMethod(e, data->cb.obj,
+ data->cb.mid[0], prompt))) {
+ TCN_ALLOC_CSTRING(o);
+ if (J2S(o)) {
+ strncpy(data->password, J2S(o), SSL_MAX_PASSWORD_LEN);
+ data->password[SSL_MAX_PASSWORD_LEN-1] = '\0';
+ rv = (int)strlen(data->password);
+ }
+ TCN_FREE_CSTRING(o);
+ }
+ }
+ else {
+#ifdef WIN32
+ rv = WIN32_SSL_password_prompt(data);
+#else
+ EVP_read_pw_string(data->password, SSL_MAX_PASSWORD_LEN,
+ data->prompt, 0);
+#endif
+ rv = (int)strlen(data->password);
+ }
+ if (rv > 0) {
+ /* Remove LF char if present */
+ char *r = strchr(data->password, '\n');
+ if (r) {
+ *r = '\0';
+ rv--;
+ }
+#ifdef WIN32
+ if ((r = strchr(data->password, '\r'))) {
+ *r = '\0';
+ rv--;
+ }
+#endif
+ }
+ return rv;
+}
+
+int SSL_password_callback(char *buf, int bufsiz, int verify,
+ void *cb)
+{
+ tcn_pass_cb_t *cb_data = (tcn_pass_cb_t *)cb;
+
+ if (buf == NULL)
+ return 0;
+ *buf = '\0';
+ if (cb_data == NULL)
+ cb_data = &tcn_password_callback;
+ if (!cb_data->prompt)
+ cb_data->prompt = SSL_DEFAULT_PASS_PROMPT;
+ if (cb_data->password[0]) {
+ /* Return already obtained password */
+ strncpy(buf, cb_data->password, bufsiz);
+ buf[bufsiz - 1] = '\0';
+ return (int)strlen(buf);
+ }
+ else {
+ if (SSL_password_prompt(cb_data) > 0)
+ strncpy(buf, cb_data->password, bufsiz);
+ }
+ buf[bufsiz - 1] = '\0';
+ return (int)strlen(buf);
+}
+
+static unsigned char dh0512_p[]={
+ 0xD9,0xBA,0xBF,0xFD,0x69,0x38,0xC9,0x51,0x2D,0x19,0x37,0x39,
+ 0xD7,0x7D,0x7E,0x3E,0x25,0x58,0x55,0x94,0x90,0x60,0x93,0x7A,
+ 0xF2,0xD5,0x61,0x5F,0x06,0xE8,0x08,0xB4,0x57,0xF4,0xCF,0xB4,
+ 0x41,0xCC,0xC4,0xAC,0xD4,0xF0,0x45,0x88,0xC9,0xD1,0x21,0x4C,
+ 0xB6,0x72,0x48,0xBD,0x73,0x80,0xE0,0xDD,0x88,0x41,0xA0,0xF1,
+ 0xEA,0x4B,0x71,0x13
+};
+static unsigned char dh1024_p[]={
+ 0xA2,0x95,0x7E,0x7C,0xA9,0xD5,0x55,0x1D,0x7C,0x77,0x11,0xAC,
+ 0xFD,0x48,0x8C,0x3B,0x94,0x1B,0xC5,0xC0,0x99,0x93,0xB5,0xDC,
+ 0xDC,0x06,0x76,0x9E,0xED,0x1E,0x3D,0xBB,0x9A,0x29,0xD6,0x8B,
+ 0x1F,0xF6,0xDA,0xC9,0xDF,0xD5,0x02,0x4F,0x09,0xDE,0xEC,0x2C,
+ 0x59,0x1E,0x82,0x32,0x80,0x9B,0xED,0x51,0x68,0xD2,0xFB,0x1E,
+ 0x25,0xDB,0xDF,0x9C,0x11,0x70,0xDF,0xCA,0x19,0x03,0x3D,0x3D,
+ 0xC1,0xAC,0x28,0x88,0x4F,0x13,0xAF,0x16,0x60,0x6B,0x5B,0x2F,
+ 0x56,0xC7,0x5B,0x5D,0xDE,0x8F,0x50,0x08,0xEC,0xB1,0xB9,0x29,
+ 0xAA,0x54,0xF4,0x05,0xC9,0xDF,0x95,0x9D,0x79,0xC6,0xEA,0x3F,
+ 0xC9,0x70,0x42,0xDA,0x90,0xC7,0xCC,0x12,0xB9,0x87,0x86,0x39,
+ 0x1E,0x1A,0xCE,0xF7,0x3F,0x15,0xB5,0x2B
+};
+static unsigned char dh2048_p[]={
+ 0xF2,0x4A,0xFC,0x7E,0x73,0x48,0x21,0x03,0xD1,0x1D,0xA8,0x16,
+ 0x87,0xD0,0xD2,0xDC,0x42,0xA8,0xD2,0x73,0xE3,0xA9,0x21,0x31,
+ 0x70,0x5D,0x69,0xC7,0x8F,0x95,0x0C,0x9F,0xB8,0x0E,0x37,0xAE,
+ 0xD1,0x6F,0x36,0x1C,0x26,0x63,0x2A,0x36,0xBA,0x0D,0x2A,0xF5,
+ 0x1A,0x0F,0xE8,0xC0,0xEA,0xD1,0xB5,0x52,0x47,0x1F,0x9A,0x0C,
+ 0x0F,0xED,0x71,0x51,0xED,0xE6,0x62,0xD5,0xF8,0x81,0x93,0x55,
+ 0xC1,0x0F,0xB4,0x72,0x64,0xB3,0x73,0xAA,0x90,0x9A,0x81,0xCE,
+ 0x03,0xFD,0x6D,0xB1,0x27,0x7D,0xE9,0x90,0x5E,0xE2,0x10,0x74,
+ 0x4F,0x94,0xC3,0x05,0x21,0x73,0xA9,0x12,0x06,0x9B,0x0E,0x20,
+ 0xD1,0x5F,0xF7,0xC9,0x4C,0x9D,0x4F,0xFA,0xCA,0x4D,0xFD,0xFF,
+ 0x6A,0x62,0x9F,0xF0,0x0F,0x3B,0xA9,0x1D,0xF2,0x69,0x29,0x00,
+ 0xBD,0xE9,0xB0,0x9D,0x88,0xC7,0x4A,0xAE,0xB0,0x53,0xAC,0xA2,
+ 0x27,0x40,0x88,0x58,0x8F,0x26,0xB2,0xC2,0x34,0x7D,0xA2,0xCF,
+ 0x92,0x60,0x9B,0x35,0xF6,0xF3,0x3B,0xC3,0xAA,0xD8,0x58,0x9C,
+ 0xCF,0x5D,0x9F,0xDB,0x14,0x93,0xFA,0xA3,0xFA,0x44,0xB1,0xB2,
+ 0x4B,0x0F,0x08,0x70,0x44,0x71,0x3A,0x73,0x45,0x8E,0x6D,0x9C,
+ 0x56,0xBC,0x9A,0xB5,0xB1,0x3D,0x8B,0x1F,0x1E,0x2B,0x0E,0x93,
+ 0xC2,0x9B,0x84,0xE2,0xE8,0xFC,0x29,0x85,0x83,0x8D,0x2E,0x5C,
+ 0xDD,0x9A,0xBB,0xFD,0xF0,0x87,0xBF,0xAF,0xC4,0xB6,0x1D,0xE7,
+ 0xF9,0x46,0x50,0x7F,0xC3,0xAC,0xFD,0xC9,0x8C,0x9D,0x66,0x6B,
+ 0x4C,0x6A,0xC9,0x3F,0x0C,0x0A,0x74,0x94,0x41,0x85,0x26,0x8F,
+ 0x9F,0xF0,0x7C,0x0B
+};
+static unsigned char dh4096_p[] = {
+ 0x8D,0xD3,0x8F,0x77,0x6F,0x6F,0xB0,0x74,0x3F,0x22,0xE9,0xD1,
+ 0x17,0x15,0x69,0xD8,0x24,0x85,0xCD,0xC4,0xE4,0x0E,0xF6,0x52,
+ 0x40,0xF7,0x1C,0x34,0xD0,0xA5,0x20,0x77,0xE2,0xFC,0x7D,0xA1,
+ 0x82,0xF1,0xF3,0x78,0x95,0x05,0x5B,0xB8,0xDB,0xB3,0xE4,0x17,
+ 0x93,0xD6,0x68,0xA7,0x0A,0x0C,0xC5,0xBB,0x9C,0x5E,0x1E,0x83,
+ 0x72,0xB3,0x12,0x81,0xA2,0xF5,0xCD,0x44,0x67,0xAA,0xE8,0xAD,
+ 0x1E,0x8F,0x26,0x25,0xF2,0x8A,0xA0,0xA5,0xF4,0xFB,0x95,0xAE,
+ 0x06,0x50,0x4B,0xD0,0xE7,0x0C,0x55,0x88,0xAA,0xE6,0xB8,0xF6,
+ 0xE9,0x2F,0x8D,0xA7,0xAD,0x84,0xBC,0x8D,0x4C,0xFE,0x76,0x60,
+ 0xCD,0xC8,0xED,0x7C,0xBF,0xF3,0xC1,0xF8,0x6A,0xED,0xEC,0xE9,
+ 0x13,0x7D,0x4E,0x72,0x20,0x77,0x06,0xA4,0x12,0xF8,0xD2,0x34,
+ 0x6F,0xDC,0x97,0xAB,0xD3,0xA0,0x45,0x8E,0x7D,0x21,0xA9,0x35,
+ 0x6E,0xE4,0xC9,0xC4,0x53,0xFF,0xE5,0xD9,0x72,0x61,0xC4,0x8A,
+ 0x75,0x78,0x36,0x97,0x1A,0xAB,0x92,0x85,0x74,0x61,0x7B,0xE0,
+ 0x92,0xB8,0xC6,0x12,0xA1,0x72,0xBB,0x5B,0x61,0xAA,0xE6,0x2C,
+ 0x2D,0x9F,0x45,0x79,0x9E,0xF4,0x41,0x93,0x93,0xEF,0x8B,0xEF,
+ 0xB7,0xBF,0x6D,0xF0,0x91,0x11,0x4F,0x7C,0x71,0x84,0xB5,0x88,
+ 0xA3,0x8C,0x1A,0xD5,0xD0,0x81,0x9C,0x50,0xAC,0xA9,0x2B,0xE9,
+ 0x92,0x2D,0x73,0x7C,0x0A,0xA3,0xFA,0xD3,0x6C,0x91,0x43,0xA6,
+ 0x80,0x7F,0xD7,0xC4,0xD8,0x6F,0x85,0xF8,0x15,0xFD,0x08,0xA6,
+ 0xF8,0x7B,0x3A,0xF4,0xD3,0x50,0xB4,0x2F,0x75,0xC8,0x48,0xB8,
+ 0xA8,0xFD,0xCA,0x8F,0x62,0xF1,0x4C,0x89,0xB7,0x18,0x67,0xB2,
+ 0x93,0x2C,0xC4,0xD4,0x71,0x29,0xA9,0x26,0x20,0xED,0x65,0x37,
+ 0x06,0x87,0xFC,0xFB,0x65,0x02,0x1B,0x3C,0x52,0x03,0xA1,0xBB,
+ 0xCF,0xE7,0x1B,0xA4,0x1A,0xE3,0x94,0x97,0x66,0x06,0xBF,0xA9,
+ 0xCE,0x1B,0x07,0x10,0xBA,0xF8,0xD4,0xD4,0x05,0xCF,0x53,0x47,
+ 0x16,0x2C,0xA1,0xFC,0x6B,0xEF,0xF8,0x6C,0x23,0x34,0xEF,0xB7,
+ 0xD3,0x3F,0xC2,0x42,0x5C,0x53,0x9A,0x00,0x52,0xCF,0xAC,0x42,
+ 0xD3,0x3B,0x2E,0xB6,0x04,0x32,0xE1,0x09,0xED,0x64,0xCD,0x6A,
+ 0x63,0x58,0xB8,0x43,0x56,0x5A,0xBE,0xA4,0x9F,0x68,0xD4,0xF7,
+ 0xC9,0x04,0xDF,0xCD,0xE5,0x93,0xB0,0x2F,0x06,0x19,0x3E,0xB8,
+ 0xAB,0x7E,0xF8,0xE7,0xE7,0xC8,0x53,0xA2,0x06,0xC3,0xC7,0xF9,
+ 0x18,0x3B,0x51,0xC3,0x9B,0xFF,0x8F,0x00,0x0E,0x87,0x19,0x68,
+ 0x2F,0x40,0xC0,0x68,0xFA,0x12,0xAE,0x57,0xB5,0xF0,0x97,0xCA,
+ 0x78,0x23,0x31,0xAB,0x67,0x7B,0x10,0x6B,0x59,0x32,0x9C,0x64,
+ 0x20,0x38,0x1F,0xC5,0x07,0x84,0x9E,0xC4,0x49,0xB1,0xDF,0xED,
+ 0x7A,0x8A,0xC3,0xE0,0xDD,0x30,0x55,0xFF,0x95,0x45,0xA6,0xEE,
+ 0xCB,0xE4,0x26,0xB9,0x8E,0x89,0x37,0x63,0xD4,0x02,0x3D,0x5B,
+ 0x4F,0xE5,0x90,0xF6,0x72,0xF8,0x10,0xEE,0x31,0x04,0x54,0x17,
+ 0xE3,0xD5,0x63,0x84,0x80,0x62,0x54,0x46,0x85,0x6C,0xD2,0xC1,
+ 0x3E,0x19,0xBD,0xE2,0x80,0x11,0x86,0xC7,0x4B,0x7F,0x67,0x86,
+ 0x47,0xD2,0x38,0xCD,0x8F,0xFE,0x65,0x3C,0x11,0xCD,0x96,0x99,
+ 0x4E,0x45,0xEB,0xEC,0x1D,0x94,0x8C,0x53,
+};
+static unsigned char dhxxx2_g[]={
+ 0x02
+};
+
+static DH *get_dh(int idx)
+{
+ DH *dh;
+
+ if ((dh = DH_new()) == NULL)
+ return NULL;
+ switch (idx) {
+ case SSL_TMP_KEY_DH_512:
+ dh->p = BN_bin2bn(dh0512_p, sizeof(dh0512_p), NULL);
+ break;
+ case SSL_TMP_KEY_DH_1024:
+ dh->p = BN_bin2bn(dh1024_p, sizeof(dh1024_p), NULL);
+ break;
+ case SSL_TMP_KEY_DH_2048:
+ dh->p = BN_bin2bn(dh2048_p, sizeof(dh2048_p), NULL);
+ break;
+ case SSL_TMP_KEY_DH_4096:
+ dh->p = BN_bin2bn(dh4096_p, sizeof(dh2048_p), NULL);
+ break;
+ }
+ dh->g = BN_bin2bn(dhxxx2_g, sizeof(dhxxx2_g), NULL);
+ if ((dh->p == NULL) || (dh->g == NULL)) {
+ DH_free(dh);
+ return NULL;
+ }
+ else
+ return dh;
+}
+
+DH *SSL_dh_get_tmp_param(int key_len)
+{
+ DH *dh;
+
+ if (key_len == 512)
+ dh = get_dh(SSL_TMP_KEY_DH_512);
+ else if (key_len == 1024)
+ dh = get_dh(SSL_TMP_KEY_DH_1024);
+ else if (key_len == 2048)
+ dh = get_dh(SSL_TMP_KEY_DH_2048);
+ else if (key_len == 4096)
+ dh = get_dh(SSL_TMP_KEY_DH_4096);
+ else
+ dh = get_dh(SSL_TMP_KEY_DH_1024);
+ return dh;
+}
+
+DH *SSL_dh_get_param_from_file(const char *file)
+{
+ DH *dh = NULL;
+ BIO *bio;
+
+ if ((bio = BIO_new_file(file, "r")) == NULL)
+ return NULL;
+ dh = PEM_read_bio_DHparams(bio, NULL, NULL, NULL);
+ BIO_free(bio);
+ return dh;
+}
+
+/*
+ * Handle out temporary RSA private keys on demand
+ *
+ * The background of this as the TLSv1 standard explains it:
+ *
+ * | D.1. Temporary RSA keys
+ * |
+ * | US Export restrictions limit RSA keys used for encryption to 512
+ * | bits, but do not place any limit on lengths of RSA keys used for
+ * | signing operations. Certificates often need to be larger than 512
+ * | bits, since 512-bit RSA keys are not secure enough for high-value
+ * | transactions or for applications requiring long-term security. Some
+ * | certificates are also designated signing-only, in which case they
+ * | cannot be used for key exchange.
+ * |
+ * | When the public key in the certificate cannot be used for encryption,
+ * | the server signs a temporary RSA key, which is then exchanged. In
+ * | exportable applications, the temporary RSA key should be the maximum
+ * | allowable length (i.e., 512 bits). Because 512-bit RSA keys are
+ * | relatively insecure, they should be changed often. For typical
+ * | electronic commerce applications, it is suggested that keys be
+ * | changed daily or every 500 transactions, and more often if possible.
+ * | Note that while it is acceptable to use the same temporary key for
+ * | multiple transactions, it must be signed each time it is used.
+ * |
+ * | RSA key generation is a time-consuming process. In many cases, a
+ * | low-priority process can be assigned the task of key generation.
+ * | Whenever a new key is completed, the existing temporary key can be
+ * | replaced with the new one.
+ *
+ * XXX: base on comment above, if thread support is enabled,
+ * we should spawn a low-priority thread to generate new keys
+ * on the fly.
+ *
+ * So we generated 512 and 1024 bit temporary keys on startup
+ * which we now just hand out on demand....
+ */
+
+RSA *SSL_callback_tmp_RSA(SSL *ssl, int export, int keylen)
+{
+ int idx;
+
+ /* doesn't matter if export flag is on,
+ * we won't be asked for keylen > 512 in that case.
+ * if we are asked for a keylen > 1024, it is too expensive
+ * to generate on the fly.
+ */
+
+ switch (keylen) {
+ case 512:
+ idx = SSL_TMP_KEY_RSA_512;
+ break;
+ case 2048:
+ idx = SSL_TMP_KEY_RSA_2048;
+ if (SSL_temp_keys[idx] == NULL)
+ idx = SSL_TMP_KEY_RSA_1024;
+ break;
+ case 4096:
+ idx = SSL_TMP_KEY_RSA_4096;
+ if (SSL_temp_keys[idx] == NULL)
+ idx = SSL_TMP_KEY_RSA_2048;
+ break;
+ case 1024:
+ default:
+ idx = SSL_TMP_KEY_RSA_1024;
+ break;
+ }
+ return (RSA *)SSL_temp_keys[idx];
+}
+
+/*
+ * Hand out the already generated DH parameters...
+ */
+DH *SSL_callback_tmp_DH(SSL *ssl, int export, int keylen)
+{
+ int idx;
+ switch (keylen) {
+ case 512:
+ idx = SSL_TMP_KEY_DH_512;
+ break;
+ case 2048:
+ idx = SSL_TMP_KEY_DH_2048;
+ break;
+ case 4096:
+ idx = SSL_TMP_KEY_DH_4096;
+ break;
+ case 1024:
+ default:
+ idx = SSL_TMP_KEY_DH_1024;
+ break;
+ }
+ return (DH *)SSL_temp_keys[idx];
+}
+
+void SSL_vhost_algo_id(const unsigned char *vhost_id, unsigned char *md, int algo)
+{
+ MD5_CTX c;
+ MD5_Init(&c);
+ MD5_Update(&c, vhost_id, MD5_DIGEST_LENGTH);
+ switch (algo) {
+ case SSL_ALGO_UNKNOWN:
+ MD5_Update(&c, "UNKNOWN", 7);
+ break;
+ case SSL_ALGO_RSA:
+ MD5_Update(&c, "RSA", 3);
+ break;
+ case SSL_ALGO_DSA:
+ MD5_Update(&c, "DSA", 3);
+ break;
+ }
+ MD5_Final(md, &c);
+}
+
+/*
+ * Read a file that optionally contains the server certificate in PEM
+ * format, possibly followed by a sequence of CA certificates that
+ * should be sent to the peer in the SSL Certificate message.
+ */
+int SSL_CTX_use_certificate_chain(SSL_CTX *ctx, const char *file,
+ int skipfirst)
+{
+ BIO *bio;
+ X509 *x509;
+ unsigned long err;
+ int n;
+ STACK *extra_certs;
+
+ if ((bio = BIO_new(BIO_s_file_internal())) == NULL)
+ return -1;
+ if (BIO_read_filename(bio, file) <= 0) {
+ BIO_free(bio);
+ return -1;
+ }
+ /* optionally skip a leading server certificate */
+ if (skipfirst) {
+ if ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) == NULL) {
+ BIO_free(bio);
+ return -1;
+ }
+ X509_free(x509);
+ }
+ /* free a perhaps already configured extra chain */
+ extra_certs = SSL_CTX_get_extra_certs(ctx);
+ if (extra_certs != NULL) {
+ sk_X509_pop_free((STACK_OF(X509) *)extra_certs, X509_free);
+ SSL_CTX_set_extra_certs(ctx,NULL);
+ }
+ /* create new extra chain by loading the certs */
+ n = 0;
+ while ((x509 = PEM_read_bio_X509(bio, NULL, NULL, NULL)) != NULL) {
+ if (!SSL_CTX_add_extra_chain_cert(ctx, x509)) {
+ X509_free(x509);
+ BIO_free(bio);
+ return -1;
+ }
+ n++;
+ }
+ /* Make sure that only the error is just an EOF */
+ if ((err = ERR_peek_error()) > 0) {
+ if (!( ERR_GET_LIB(err) == ERR_LIB_PEM
+ && ERR_GET_REASON(err) == PEM_R_NO_START_LINE)) {
+ BIO_free(bio);
+ return -1;
+ }
+ while (ERR_get_error() > 0) ;
+ }
+ BIO_free(bio);
+ return n;
+}
+
+static int ssl_X509_STORE_lookup(X509_STORE *store, int yype,
+ X509_NAME *name, X509_OBJECT *obj)
+{
+ X509_STORE_CTX ctx;
+ int rc;
+
+ X509_STORE_CTX_init(&ctx, store, NULL, NULL);
+ rc = X509_STORE_get_by_subject(&ctx, yype, name, obj);
+ X509_STORE_CTX_cleanup(&ctx);
+ return rc;
+}
+
+static int ssl_verify_CRL(int ok, X509_STORE_CTX *ctx, tcn_ssl_conn_t *con)
+{
+ X509_OBJECT obj;
+ X509_NAME *subject, *issuer;
+ X509 *cert;
+ X509_CRL *crl;
+ EVP_PKEY *pubkey;
+ int i, n, rc;
+
+ /*
+ * Determine certificate ingredients in advance
+ */
+ cert = X509_STORE_CTX_get_current_cert(ctx);
+ subject = X509_get_subject_name(cert);
+ issuer = X509_get_issuer_name(cert);
+
+ /*
+ * OpenSSL provides the general mechanism to deal with CRLs but does not
+ * use them automatically when verifying certificates, so we do it
+ * explicitly here. We will check the CRL for the currently checked
+ * certificate, if there is such a CRL in the store.
+ *
+ * We come through this procedure for each certificate in the certificate
+ * chain, starting with the root-CA's certificate. At each step we've to
+ * both verify the signature on the CRL (to make sure it's a valid CRL)
+ * and it's revocation list (to make sure the current certificate isn't
+ * revoked). But because to check the signature on the CRL we need the
+ * public key of the issuing CA certificate (which was already processed
+ * one round before), we've a little problem. But we can both solve it and
+ * at the same time optimize the processing by using the following
+ * verification scheme (idea and code snippets borrowed from the GLOBUS
+ * project):
+ *
+ * 1. We'll check the signature of a CRL in each step when we find a CRL
+ * through the _subject_ name of the current certificate. This CRL
+ * itself will be needed the first time in the next round, of course.
+ * But we do the signature processing one round before this where the
+ * public key of the CA is available.
+ *
+ * 2. We'll check the revocation list of a CRL in each step when
+ * we find a CRL through the _issuer_ name of the current certificate.
+ * This CRLs signature was then already verified one round before.
+ *
+ * This verification scheme allows a CA to revoke its own certificate as
+ * well, of course.
+ */
+
+ /*
+ * Try to retrieve a CRL corresponding to the _subject_ of
+ * the current certificate in order to verify it's integrity.
+ */
+ memset((char *)&obj, 0, sizeof(obj));
+ rc = ssl_X509_STORE_lookup(con->ctx->crl,
+ X509_LU_CRL, subject, &obj);
+ crl = obj.data.crl;
+
+ if ((rc > 0) && crl) {
+ /*
+ * Log information about CRL
+ * (A little bit complicated because of ASN.1 and BIOs...)
+ */
+ /*
+ * Verify the signature on this CRL
+ */
+ pubkey = X509_get_pubkey(cert);
+ rc = X509_CRL_verify(crl, pubkey);
+ /* Only refcounted in OpenSSL */
+ if (pubkey)
+ EVP_PKEY_free(pubkey);
+ if (rc <= 0) {
+ /* TODO: Log Invalid signature on CRL */
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_SIGNATURE_FAILURE);
+ X509_OBJECT_free_contents(&obj);
+ return 0;
+ }
+
+ /*
+ * Check date of CRL to make sure it's not expired
+ */
+ i = X509_cmp_current_time(X509_CRL_get_nextUpdate(crl));
+
+ if (i == 0) {
+ /* TODO: Log Found CRL has invalid nextUpdate field */
+
+ X509_STORE_CTX_set_error(ctx,
+ X509_V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD);
+ X509_OBJECT_free_contents(&obj);
+ return 0;
+ }
+
+ if (i < 0) {
+ /* TODO: Log Found CRL is expired */
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CRL_HAS_EXPIRED);
+ X509_OBJECT_free_contents(&obj);
+
+ return 0;
+ }
+
+ X509_OBJECT_free_contents(&obj);
+ }
+
+ /*
+ * Try to retrieve a CRL corresponding to the _issuer_ of
+ * the current certificate in order to check for revocation.
+ */
+ memset((char *)&obj, 0, sizeof(obj));
+ rc = ssl_X509_STORE_lookup(con->ctx->crl,
+ X509_LU_CRL, issuer, &obj);
+
+ crl = obj.data.crl;
+ if ((rc > 0) && crl) {
+ /*
+ * Check if the current certificate is revoked by this CRL
+ */
+ n = sk_X509_REVOKED_num(X509_CRL_get_REVOKED(crl));
+
+ for (i = 0; i < n; i++) {
+ X509_REVOKED *revoked =
+ sk_X509_REVOKED_value(X509_CRL_get_REVOKED(crl), i);
+
+ ASN1_INTEGER *sn = revoked->serialNumber;
+
+ if (!ASN1_INTEGER_cmp(sn, X509_get_serialNumber(cert))) {
+ X509_STORE_CTX_set_error(ctx, X509_V_ERR_CERT_REVOKED);
+ X509_OBJECT_free_contents(&obj);
+
+ return 0;
+ }
+ }
+
+ X509_OBJECT_free_contents(&obj);
+ }
+
+ return ok;
+}
+
+/*
+ * This OpenSSL callback function is called when OpenSSL
+ * does client authentication and verifies the certificate chain.
+ */
+int SSL_callback_SSL_verify(int ok, X509_STORE_CTX *ctx)
+{
+ /* Get Apache context back through OpenSSL context */
+ SSL *ssl = X509_STORE_CTX_get_ex_data(ctx,
+ SSL_get_ex_data_X509_STORE_CTX_idx());
+ tcn_ssl_conn_t *con = (tcn_ssl_conn_t *)SSL_get_app_data(ssl);
+ /* Get verify ingredients */
+ int errnum = X509_STORE_CTX_get_error(ctx);
+ int errdepth = X509_STORE_CTX_get_error_depth(ctx);
+ int verify = con->ctx->verify_mode;
+ int depth = con->ctx->verify_depth;
+
+ if (verify == SSL_CVERIFY_UNSET ||
+ verify == SSL_CVERIFY_NONE)
+ return 1;
+
+ if (SSL_VERIFY_ERROR_IS_OPTIONAL(errnum) &&
+ (verify == SSL_CVERIFY_OPTIONAL_NO_CA)) {
+ ok = 1;
+ SSL_set_verify_result(ssl, X509_V_OK);
+ }
+ /*
+ * Additionally perform CRL-based revocation checks
+ */
+ if (ok && con->ctx->crl) {
+ if (!(ok = ssl_verify_CRL(ok, ctx, con))) {
+ errnum = X509_STORE_CTX_get_error(ctx);
+ /* TODO: Log something */
+ }
+ }
+ /*
+ * If we already know it's not ok, log the real reason
+ */
+ if (!ok) {
+ /* TODO: Some logging
+ * Certificate Verification: Error
+ */
+ if (con->peer) {
+ X509_free(con->peer);
+ con->peer = NULL;
+ }
+ }
+ if (errdepth > depth) {
+ /* TODO: Some logging
+ * Certificate Verification: Certificate Chain too long
+ */
+ ok = 0;
+ }
+ return ok;
+}
+
+#else
+/* OpenSSL is not supported
+ * If someday we make OpenSSL optional
+ * APR_ENOTIMPL will go here
+ */
+#error "No OpenSSL Toolkit defined."
+#endif
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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"
+
+extern int tcn_parent_pid;
+
+TCN_IMPLEMENT_CALL(jlong, Stdlib, malloc)(TCN_STDARGS, jint size)
+{
+ UNREFERENCED_STDARGS;
+ if (size)
+ return P2J(malloc((size_t)size));
+ else
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Stdlib, realloc)(TCN_STDARGS, jlong mem, jint size)
+{
+ void *ptr = J2P(mem, void *);
+ UNREFERENCED_STDARGS;
+ if (size)
+ return P2J(realloc(ptr, (size_t)size));
+ else
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Stdlib, calloc)(TCN_STDARGS, jint num, jint size)
+{
+ UNREFERENCED_STDARGS;
+ if (num && size)
+ return P2J(calloc((size_t)num, (size_t)size));
+ else
+ return 0;
+}
+
+TCN_IMPLEMENT_CALL(void, Stdlib, free)(TCN_STDARGS, jlong mem)
+{
+ void *ptr = J2P(mem, void *);
+
+ UNREFERENCED_STDARGS;
+ if (ptr)
+ free(ptr);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Stdlib, memread)(TCN_STDARGS,
+ jbyteArray dst,
+ jlong src, jint sz)
+{
+ jbyte *s = J2P(src, jbyte *);
+ jbyte *dest = (*e)->GetPrimitiveArrayCritical(e, dst, NULL);
+
+ UNREFERENCED(o);
+ if (s && dest) {
+ memcpy(dest, s, (size_t)sz);
+ (*e)->ReleasePrimitiveArrayCritical(e, dst, dest, 0);
+ return JNI_TRUE;
+ }
+ else
+ return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Stdlib, memwrite)(TCN_STDARGS, jlong dst,
+ jbyteArray src, jint sz)
+{
+ jbyte *dest = J2P(dst, jbyte *);
+ jbyte *s = (*e)->GetPrimitiveArrayCritical(e, src, NULL);
+
+ UNREFERENCED(o);
+ if (s && dest) {
+ memcpy(dest, s, (size_t)sz);
+ (*e)->ReleasePrimitiveArrayCritical(e, src, s, JNI_ABORT);
+ return JNI_TRUE;
+ }
+ else
+ return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Stdlib, memset)(TCN_STDARGS, jlong dst,
+ jint c, jint sz)
+{
+ jbyte *dest = J2P(dst, jbyte *);
+
+ UNREFERENCED_STDARGS;
+ if (memset(dest, (int)c, (size_t)sz))
+ return JNI_TRUE;
+ else
+ return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, Stdlib, getpid)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ return (jint)getpid();
+}
+
+TCN_IMPLEMENT_CALL(jint, Stdlib, getppid)(TCN_STDARGS)
+{
+ UNREFERENCED_STDARGS;
+ return (jint)tcn_parent_pid;
+}
+
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ * http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/*\r
+ *\r
+ * @author Mladen Turk\r
+ * @version $Revision: 393735 $, $Date: 2006-04-13 08:41:49 +0200 (čet, 13 tra 2006) $\r
+ */\r
+\r
+#include "tcn.h"\r
+\r
+TCN_IMPLEMENT_CALL(jlong, Thread, current)(TCN_STDARGS)\r
+{\r
+ UNREFERENCED_STDARGS;\r
+ return (jlong)((unsigned long)apr_os_thread_current());\r
+}\r
--- /dev/null
+/* Copyright 2000-2005 The Apache Software Foundation
+ *
+ * Licensed 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_user.h"
+#include "apr_network_io.h"
+
+TCN_IMPLEMENT_CALL(jlong, User, uidCurrent)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_uid_t uid;
+ apr_gid_t gid;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_uid_current(&uid, &gid, p), uid);
+
+cleanup:
+ return (jlong)uid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, gidCurrent)(TCN_STDARGS, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_uid_t uid;
+ apr_gid_t gid;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_uid_current(&uid, &gid, p), gid);
+
+cleanup:
+ return (jlong)gid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, uid)(TCN_STDARGS, jstring uname, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_uid_t uid;
+ apr_gid_t gid;
+ TCN_ALLOC_CSTRING(uname);
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_uid_get(&uid, &gid, J2S(uname), p), uid);
+
+cleanup:
+ TCN_FREE_CSTRING(uname);
+ return (jlong)uid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, usergid)(TCN_STDARGS, jstring uname,
+ jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_uid_t uid;
+ apr_gid_t gid;
+ TCN_ALLOC_CSTRING(uname);
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_uid_get(&uid, &gid, J2S(uname), p), gid);
+
+cleanup:
+ TCN_FREE_CSTRING(uname);
+ return (jlong)gid;
+}
+
+TCN_IMPLEMENT_CALL(jlong, User, gid)(TCN_STDARGS, jstring gname, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_gid_t gid;
+ TCN_ALLOC_CSTRING(gname);
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR( apr_gid_get(&gid, J2S(gname), p), gid);
+
+cleanup:
+ TCN_FREE_CSTRING(gname);
+ return (jlong)gid;
+}
+
+TCN_IMPLEMENT_CALL(jstring, User, username)(TCN_STDARGS, jlong userid, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_uid_t uid = (apr_uid_t)userid;
+ char *uname = NULL;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_uid_name_get(&uname, uid, p), uname);
+
+cleanup:
+ if (uname)
+ return AJP_TO_JSTRING(uname);
+ else
+ return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jstring, User, groupname)(TCN_STDARGS, jlong grpid, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ apr_gid_t gid = (apr_uid_t)grpid;
+ char *gname = NULL;
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_gid_name_get(&gname, gid, p), gname);
+
+cleanup:
+ if (gname)
+ return AJP_TO_JSTRING(gname);
+ else
+ return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jint, User,uidcompare)(TCN_STDARGS, jlong left, jlong right)
+{
+
+ UNREFERENCED_STDARGS;
+ return (int)apr_uid_compare((apr_uid_t)left,
+ (apr_uid_t)right);
+}
+
+TCN_IMPLEMENT_CALL(jint, User,gidcompare)(TCN_STDARGS, jlong left, jlong right)
+{
+
+ UNREFERENCED_STDARGS;
+ return (int)apr_gid_compare((apr_gid_t)left,
+ (apr_gid_t)right);
+}
+
+TCN_IMPLEMENT_CALL(jstring, User, homepath)(TCN_STDARGS, jstring uname, jlong pool)
+{
+ apr_pool_t *p = J2P(pool, apr_pool_t *);
+ char *dirname = NULL;
+ TCN_ALLOC_CSTRING(uname);
+
+ UNREFERENCED(o);
+ TCN_THROW_IF_ERR(apr_uid_homepath_get(&dirname, J2S(uname),
+ p), dirname);
+
+cleanup:
+ TCN_FREE_CSTRING(uname);
+ if (dirname)
+ return AJP_TO_JSTRING(dirname);
+ else
+ return NULL;
+}
+
--- /dev/null
+# Microsoft Developer Studio Project File - Name="tcnative" - Package Owner=<4>
+# Microsoft Developer Studio Generated Build File, Format Version 6.00
+# ** DO NOT EDIT **
+
+# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
+
+CFG=tcnative - Win32 Debug
+!MESSAGE This is not a valid makefile. To build this project using NMAKE,
+!MESSAGE use the Export Makefile command and run
+!MESSAGE
+!MESSAGE NMAKE /f "tcnative.mak".
+!MESSAGE
+!MESSAGE You can specify a configuration when running NMAKE
+!MESSAGE by defining the macro CFG on the command line. For example:
+!MESSAGE
+!MESSAGE NMAKE /f "tcnative.mak" CFG="tcnative - Win32 Debug"
+!MESSAGE
+!MESSAGE Possible choices for configuration are:
+!MESSAGE
+!MESSAGE "tcnative - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE "tcnative - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
+!MESSAGE
+
+# Begin Project
+# PROP AllowPerConfigDependencies 0
+# PROP Scc_ProjName ""
+# PROP Scc_LocalPath ""
+CPP=cl.exe
+MTL=midl.exe
+RSC=rc.exe
+
+!IF "$(CFG)" == "tcnative - Win32 Release"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 0
+# PROP BASE Output_Dir "Release"
+# PROP BASE Intermediate_Dir "Release"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 0
+# PROP Output_Dir "LibR"
+# PROP Intermediate_Dir "LibR"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MD /W3 /Zi /O2 /Oy- /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MD /W3 /Zi /O2 /Oy- /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "NDEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "APR_DECLARE_STATIC" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"LibR\tcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "NDEBUG"
+# ADD RSC /l 0x409 /d "NDEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /opt:ref
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /debug /machine:I386 /out:"LibR/tcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll" /opt:ref
+
+!ELSEIF "$(CFG)" == "tcnative - Win32 Debug"
+
+# PROP BASE Use_MFC 0
+# PROP BASE Use_Debug_Libraries 1
+# PROP BASE Output_Dir "Debug"
+# PROP BASE Intermediate_Dir "Debug"
+# PROP BASE Target_Dir ""
+# PROP Use_MFC 0
+# PROP Use_Debug_Libraries 1
+# PROP Output_Dir "LibD"
+# PROP Intermediate_Dir "LibD"
+# PROP Ignore_Export_Lib 0
+# PROP Target_Dir ""
+# ADD BASE CPP /nologo /MDd /W3 /GX /Zi /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /FD /c
+# ADD CPP /nologo /MDd /W4 /GX /Zi /Od /I "./include" /I "../apr/include" /I "../apr/include/arch/win32" /I "$(JAVA_HOME)/include" /I "$(JAVA_HOME)/include/win32" /I "../openssl/inc32" /D "_DEBUG" /D "TCN_DECLARE_EXPORT" /D "WIN32" /D "_WINDOWS" /D "APR_DECLARE_STATIC" /D "NO_IDEA" /D "NO_RC5" /D "NO_MDC2" /D "OPENSSL_NO_IDEA" /D "OPENSSL_NO_RC5" /D "OPENSSL_NO_MDC2" /D "HAVE_OPENSSL" /D HAVE_SSL_SET_STATE=1 /Fd"LibD\tcnative_src" /FD /c
+# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /o /win32 "NUL"
+# ADD BASE RSC /l 0x409 /d "_DEBUG"
+# ADD RSC /l 0x409 /d "_DEBUG"
+BSC32=bscmake.exe
+# ADD BASE BSC32 /nologo
+# ADD BSC32 /nologo
+LINK32=link.exe
+# ADD BASE LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386
+# ADD LINK32 kernel32.lib advapi32.lib ws2_32.lib mswsock.lib wldap32.lib psapi.lib ole32.lib shlwapi.lib libeay32.lib ssleay32.lib /nologo /base:"0x6EE00000" /subsystem:windows /dll /incremental:no /debug /machine:I386 /out:"LibD/tcnative-1.dll" /libpath:"../openssl/out32" /libpath:"../openssl/out32dll"
+
+!ENDIF
+
+# Begin Target
+
+# Name "tcnative - Win32 Release"
+# Name "tcnative - Win32 Debug"
+# Begin Group "Source Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\src\address.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\dir.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\error.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\file.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\info.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\jnilib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\lock.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\misc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\mmap.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\multicast.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\network.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\poll.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\pool.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\proc.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\shm.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\ssl.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslcontext.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslinfo.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslnetwork.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\sslutils.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\stdlib.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\thread.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\src\user.c
+# End Source File
+# End Group
+# Begin Group "Generated Files"
+
+# PROP Default_Filter ""
+# End Group
+# Begin Group "Header Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\include\ssl_private.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_api.h
+# End Source File
+# Begin Source File
+
+SOURCE=.\include\tcn_version.h
+# End Source File
+# End Group
+# Begin Group "Platform Files"
+
+# PROP Default_Filter ""
+# Begin Source File
+
+SOURCE=.\os\win32\ntpipe.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\registry.c
+# End Source File
+# Begin Source File
+
+SOURCE=.\os\win32\system.c
+# End Source File
+# End Group
+# Begin Source File
+
+SOURCE=.\os\win32\libtcnative.rc
+# End Source File
+# End Target
+# End Project
--- /dev/null
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+TCNATIVE_MAJOR_VERSION=@TCNATIVE_MAJOR_VERSION@
+includedir=@includedir@
+
+Name: Tomcat native Java
+Description: Companion Native Java library
+Version: @TCNATIVE_DOTTED_VERSION@
+# assume that tcnative requires libapr of same major version
+Requires: apr-@TCNATIVE_MAJOR_VERSION@
+Libs: -L${libdir} -l@TCNATIVE_LIBNAME@ @TCNATIVE_EXPORT_LIBS@
+Cflags: -I${includedir}