From: mturk Date: Wed, 18 Oct 2006 11:09:50 +0000 (+0000) Subject: Copy the tomcat-connector/jni/native to the native/connector. X-Git-Url: https://git.internetallee.de/?a=commitdiff_plain;h=eea09b45a6a074934532ec76a6290a044fa41ae2;p=tomcat7.0 Copy the tomcat-connector/jni/native to the native/connector. git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@465208 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/native/connector/BUILDING b/native/connector/BUILDING new file mode 100644 index 000000000..7f9e7b380 --- /dev/null +++ b/native/connector/BUILDING @@ -0,0 +1,30 @@ + 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 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 diff --git a/native/connector/Makefile.in b/native/connector/Makefile.in new file mode 100644 index 000000000..4e75af980 --- /dev/null +++ b/native/connector/Makefile.in @@ -0,0 +1,65 @@ +# +# 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) diff --git a/native/connector/build.conf b/native/connector/build.conf new file mode 100644 index 000000000..900ec4f21 --- /dev/null +++ b/native/connector/build.conf @@ -0,0 +1,19 @@ +# +# 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 diff --git a/native/connector/build/buildcheck.sh b/native/connector/build/buildcheck.sh new file mode 100644 index 000000000..cd1d593aa --- /dev/null +++ b/native/connector/build/buildcheck.sh @@ -0,0 +1,72 @@ +#! /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 diff --git a/native/connector/build/get-version.sh b/native/connector/build/get-version.sh new file mode 100755 index 000000000..fd685b22a --- /dev/null +++ b/native/connector/build/get-version.sh @@ -0,0 +1,37 @@ +#!/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 diff --git a/native/connector/build/lineends.pl b/native/connector/build/lineends.pl new file mode 100644 index 000000000..f91a9d30c --- /dev/null +++ b/native/connector/build/lineends.pl @@ -0,0 +1,149 @@ +#!/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; + } +} diff --git a/native/connector/build/mkdir.sh b/native/connector/build/mkdir.sh new file mode 100644 index 000000000..b947c9260 --- /dev/null +++ b/native/connector/build/mkdir.sh @@ -0,0 +1,37 @@ +#!/bin/sh +## +## mkdir.sh -- make directory hierarchy +## +## Based on `mkinstalldirs' from Noah Friedman +## 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 +## +# +# 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 + diff --git a/native/connector/build/rpm/tcnative.spec.in b/native/connector/build/rpm/tcnative.spec.in new file mode 100644 index 000000000..26969e859 --- /dev/null +++ b/native/connector/build/rpm/tcnative.spec.in @@ -0,0 +1,78 @@ + +%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 1.0.0-1 +- update to support v1.0.2 of APR + diff --git a/native/connector/build/tcnative.m4 b/native/connector/build/tcnative.m4 new file mode 100644 index 000000000..c6f266f30 --- /dev/null +++ b/native/connector/build/tcnative.m4 @@ -0,0 +1,343 @@ +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=" 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 ],[ +#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) +]) diff --git a/native/connector/buildconf b/native/connector/buildconf new file mode 100755 index 000000000..c5a104937 --- /dev/null +++ b/native/connector/buildconf @@ -0,0 +1,95 @@ +#!/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 + diff --git a/native/connector/config.layout b/native/connector/config.layout new file mode 100644 index 000000000..61422fc9a --- /dev/null +++ b/native/connector/config.layout @@ -0,0 +1,248 @@ +## +## 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 +## `/' suffix where is currently hardcoded to 'apr'. +## (This may become a configurable parameter at some point.) +## + +# Generic path layout that needs --prefix=/some/path + + 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} + + +# Classical Tomcat Native path layout designed for parallel installs. + + 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} + + +# Classical single-installation APR path layout. + + 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} + + +# GNU standards conforming path layout. +# See FSF's GNU project `make-stds' document for details. + + 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 + + +# Mac OS X Server (Rhapsody) + + 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 + + +# Darwin/Mac OS Layout + + 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 + + +# Red Hat Linux 7.x layout + + 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 + + +# According to the /opt filesystem conventions + + 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 + + +# BeOS layout... + + 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 + + +# SuSE 6.x layout + + 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 + + +# BSD/OS layout + + 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 + + +# Solaris 8 Layout + + 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 + + +# OpenBSD Layout + + 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 + + +# Debian layout + + 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 + diff --git a/native/connector/configure.in b/native/connector/configure.in new file mode 100644 index 000000000..0956d24ef --- /dev/null +++ b/native/connector/configure.in @@ -0,0 +1,232 @@ +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 +]) diff --git a/native/connector/include/ssl_private.h b/native/connector/include/ssl_private.h new file mode 100644 index 000000000..7ecfe289e --- /dev/null +++ b/native/connector/include/ssl_private.h @@ -0,0 +1,293 @@ +/* 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 +#include +#include +#include +#include +#include +#include +#include +#include +/* 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 +#endif + +#ifndef RAND_MAX +#include +#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 */ diff --git a/native/connector/include/tcn.h b/native/connector/include/tcn.h new file mode 100644 index 000000000..5cc4b8586 --- /dev/null +++ b/native/connector/include/tcn.h @@ -0,0 +1,284 @@ +/* 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 +#include +#if defined(_WIN32) && !defined(__CYGWIN__) +#include +#else +#include +#endif + +#include "tcn_api.h" + + +#if defined(_DEBUG) || defined(DEBUG) +#include +#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 */ diff --git a/native/connector/include/tcn_api.h b/native/connector/include/tcn_api.h new file mode 100644 index 000000000..70dbb7b0c --- /dev/null +++ b/native/connector/include/tcn_api.h @@ -0,0 +1,166 @@ +/* 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 + +/** + * 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 */ diff --git a/native/connector/include/tcn_version.h b/native/connector/include/tcn_version.h new file mode 100644 index 000000000..9154d7099 --- /dev/null +++ b/native/connector/include/tcn_version.h @@ -0,0 +1,98 @@ +/* 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 */ diff --git a/native/connector/libtcnative.dsp b/native/connector/libtcnative.dsp new file mode 100644 index 000000000..0e5d06950 --- /dev/null +++ b/native/connector/libtcnative.dsp @@ -0,0 +1,231 @@ +# 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 diff --git a/native/connector/libtcnative.dsw b/native/connector/libtcnative.dsw new file mode 100644 index 000000000..042257e81 --- /dev/null +++ b/native/connector/libtcnative.dsw @@ -0,0 +1,71 @@ +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> +{{{ +}}} + +############################################################################### + diff --git a/native/connector/os/netware/system.c b/native/connector/os/netware/system.c new file mode 100644 index 000000000..a77081625 --- /dev/null +++ b/native/connector/os/netware/system.c @@ -0,0 +1,44 @@ +/* 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; +} diff --git a/native/connector/os/unix/system.c b/native/connector/os/unix/system.c new file mode 100644 index 000000000..ba8cbb63d --- /dev/null +++ b/native/connector/os/unix/system.c @@ -0,0 +1,384 @@ +/* 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 +#elif defined(sun) +#include +#include +#include +#include +#include +#endif + +#if defined(DARWIN) +#include +#include +#include +#include +#include +#endif + +#include +#include + +#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); +} diff --git a/native/connector/os/unix/uxpipe.c b/native/connector/os/unix/uxpipe.c new file mode 100644 index 000000000..19a579865 --- /dev/null +++ b/native/connector/os/unix/uxpipe.c @@ -0,0 +1,354 @@ +/* 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 +#include /* 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; +} diff --git a/native/connector/os/win32/apache.ico b/native/connector/os/win32/apache.ico new file mode 100644 index 000000000..bfb4f63ab Binary files /dev/null and b/native/connector/os/win32/apache.ico differ diff --git a/native/connector/os/win32/libtcnative.rc b/native/connector/os/win32/libtcnative.rc new file mode 100644 index 000000000..e239e1202 --- /dev/null +++ b/native/connector/os/win32/libtcnative.rc @@ -0,0 +1,69 @@ +#include + +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 diff --git a/native/connector/os/win32/logmessages.bin b/native/connector/os/win32/logmessages.bin new file mode 100644 index 000000000..44ce98505 Binary files /dev/null and b/native/connector/os/win32/logmessages.bin differ diff --git a/native/connector/os/win32/logmessages.mc b/native/connector/os/win32/logmessages.mc new file mode 100644 index 000000000..68f86f644 --- /dev/null +++ b/native/connector/os/win32/logmessages.mc @@ -0,0 +1,41 @@ +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 +. diff --git a/native/connector/os/win32/ntpipe.c b/native/connector/os/win32/ntpipe.c new file mode 100644 index 000000000..2c40f3164 --- /dev/null +++ b/native/connector/os/win32/ntpipe.c @@ -0,0 +1,505 @@ +/* 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 +#include +#include +#include + +#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; +} diff --git a/native/connector/os/win32/registry.c b/native/connector/os/win32/registry.c new file mode 100644 index 000000000..32fcd436d --- /dev/null +++ b/native/connector/os/win32/registry.c @@ -0,0 +1,788 @@ +/* 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 +#include +#include +#include + +#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; +} diff --git a/native/connector/os/win32/system.c b/native/connector/os/win32/system.c new file mode 100644 index 000000000..5a85d43e0 --- /dev/null +++ b/native/connector/os/win32/system.c @@ -0,0 +1,463 @@ +/* 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 +#include +#include +#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 +#endif +#include +#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); +} + + diff --git a/native/connector/src/address.c b/native/connector/src/address.c new file mode 100644 index 000000000..41e47972a --- /dev/null +++ b/native/connector/src/address.c @@ -0,0 +1,105 @@ +/* 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: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $ + */ + +#include "tcn.h" + +TCN_IMPLEMENT_CALL(jlong, Address, info)(TCN_STDARGS, + jstring hostname, + jint family, jint port, + jint flags, jlong pool) +{ + apr_pool_t *p = J2P(pool, apr_pool_t *); + TCN_ALLOC_CSTRING(hostname); + apr_sockaddr_t *sa = NULL; + apr_int32_t f; + + + UNREFERENCED(o); + GET_S_FAMILY(f, family); + TCN_THROW_IF_ERR(apr_sockaddr_info_get(&sa, + J2S(hostname), f, (apr_port_t)port, + (apr_int32_t)flags, p), sa); + +cleanup: + TCN_FREE_CSTRING(hostname); + return P2J(sa); +} + +TCN_IMPLEMENT_CALL(jstring, Address, getnameinfo)(TCN_STDARGS, + jlong sa, jint flags) +{ + apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *); + char *hostname; + + UNREFERENCED(o); + if (apr_getnameinfo(&hostname, s, (apr_int32_t)flags) == APR_SUCCESS) + return AJP_TO_JSTRING(hostname); + else + return NULL; +} + +TCN_IMPLEMENT_CALL(jstring, Address, getip)(TCN_STDARGS, jlong sa) +{ + apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *); + char *ipaddr; + + UNREFERENCED(o); + if (apr_sockaddr_ip_get(&ipaddr, s) == APR_SUCCESS) + return AJP_TO_JSTRING(ipaddr); + else + return NULL; +} + +TCN_IMPLEMENT_CALL(jlong, Address, get)(TCN_STDARGS, jint which, + jlong sock) +{ + tcn_socket_t *s = J2P(sock, tcn_socket_t *); + apr_sockaddr_t *sa = NULL; + + UNREFERENCED(o); + TCN_THROW_IF_ERR(apr_socket_addr_get(&sa, + (apr_interface_e)which, s->sock), sa); +cleanup: + return P2J(sa); +} + +TCN_IMPLEMENT_CALL(jint, Address, equal)(TCN_STDARGS, + jlong a, jlong b) +{ + apr_sockaddr_t *sa = J2P(a, apr_sockaddr_t *); + apr_sockaddr_t *sb = J2P(b, apr_sockaddr_t *); + + UNREFERENCED_STDARGS; + return apr_sockaddr_equal(sa, sb) ? JNI_TRUE : JNI_FALSE; +} + +TCN_IMPLEMENT_CALL(jint, Address, getservbyname)(TCN_STDARGS, + jlong sa, jstring servname) +{ + apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *); + TCN_ALLOC_CSTRING(servname); + apr_status_t rv; + + UNREFERENCED(o); + rv = apr_getservbyname(s, J2S(servname)); + TCN_FREE_CSTRING(servname); + return (jint)rv; +} diff --git a/native/connector/src/dir.c b/native/connector/src/dir.c new file mode 100644 index 000000000..49000391f --- /dev/null +++ b/native/connector/src/dir.c @@ -0,0 +1,104 @@ +/* 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); +} diff --git a/native/connector/src/error.c b/native/connector/src/error.c new file mode 100644 index 000000000..20bdc5974 --- /dev/null +++ b/native/connector/src/error.c @@ -0,0 +1,247 @@ +/* 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, + "", + "(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; +} diff --git a/native/connector/src/file.c b/native/connector/src/file.c new file mode 100644 index 000000000..ff669b441 --- /dev/null +++ b/native/connector/src/file.c @@ -0,0 +1,600 @@ +/* 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); +} diff --git a/native/connector/src/info.c b/native/connector/src/info.c new file mode 100644 index 000000000..76716c505 --- /dev/null +++ b/native/connector/src/info.c @@ -0,0 +1,351 @@ +/* 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, + "", "()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, + "", "()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; +} diff --git a/native/connector/src/jnilib.c b/native/connector/src/jnilib.c new file mode 100644 index 000000000..c48647bca --- /dev/null +++ b/native/connector/src/jnilib.c @@ -0,0 +1,469 @@ +/* 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, + "", "([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; +} diff --git a/native/connector/src/lock.c b/native/connector/src/lock.c new file mode 100644 index 000000000..b93cd61cb --- /dev/null +++ b/native/connector/src/lock.c @@ -0,0 +1,201 @@ +/* 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); +} + diff --git a/native/connector/src/misc.c b/native/connector/src/misc.c new file mode 100644 index 000000000..d9c7c2aaf --- /dev/null +++ b/native/connector/src/misc.c @@ -0,0 +1,80 @@ +/* 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; +} diff --git a/native/connector/src/mmap.c b/native/connector/src/mmap.c new file mode 100644 index 000000000..c4e96e4f3 --- /dev/null +++ b/native/connector/src/mmap.c @@ -0,0 +1,101 @@ +/* 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 +} diff --git a/native/connector/src/multicast.c b/native/connector/src/multicast.c new file mode 100644 index 000000000..1306c9cec --- /dev/null +++ b/native/connector/src/multicast.c @@ -0,0 +1,71 @@ +/* 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: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $ + */ + +#include "tcn.h" + +TCN_IMPLEMENT_CALL(jint, Mulicast, join)(TCN_STDARGS, + jlong sock, jlong join, + jlong iface, jlong source) +{ + tcn_socket_t *s = J2P(sock, tcn_socket_t *); + apr_sockaddr_t *ja = J2P(join, apr_sockaddr_t *); + apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *); + apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *); + UNREFERENCED_STDARGS; + return (jint)apr_mcast_join(s->sock, ja, ia, sa); +}; + +TCN_IMPLEMENT_CALL(jint, Mulicast, leave)(TCN_STDARGS, + jlong sock, jlong addr, + jlong iface, jlong source) +{ + tcn_socket_t *s = J2P(sock, tcn_socket_t *); + apr_sockaddr_t *aa = J2P(addr, apr_sockaddr_t *); + apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *); + apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *); + UNREFERENCED_STDARGS; + return (jint)apr_mcast_leave(s->sock, aa, ia, sa); +}; + +TCN_IMPLEMENT_CALL(jint, Mulicast, hops)(TCN_STDARGS, + jlong sock, jint ttl) +{ + tcn_socket_t *s = J2P(sock, tcn_socket_t *); + UNREFERENCED_STDARGS; + return (jint)apr_mcast_hops(s->sock, (apr_byte_t)ttl); +}; + +TCN_IMPLEMENT_CALL(jint, Mulicast, loopback)(TCN_STDARGS, + jlong sock, jboolean opt) +{ + tcn_socket_t *s = J2P(sock, tcn_socket_t *); + UNREFERENCED_STDARGS; + return (jint)apr_mcast_loopback(s->sock, opt == JNI_TRUE ? 1 : 0); +}; + +TCN_IMPLEMENT_CALL(jint, Mulicast, ointerface)(TCN_STDARGS, + jlong sock, jlong iface) +{ + tcn_socket_t *s = J2P(sock, tcn_socket_t *); + apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *); + UNREFERENCED_STDARGS; + return (jint)apr_mcast_interface(s->sock, ia); +}; diff --git a/native/connector/src/network.c b/native/connector/src/network.c new file mode 100644 index 000000000..89c623679 --- /dev/null +++ b/native/connector/src/network.c @@ -0,0 +1,1211 @@ +/* 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; +} diff --git a/native/connector/src/os.c b/native/connector/src/os.c new file mode 100644 index 000000000..703e74042 --- /dev/null +++ b/native/connector/src/os.c @@ -0,0 +1,39 @@ +/* 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)); +} + diff --git a/native/connector/src/poll.c b/native/connector/src/poll.c new file mode 100644 index 000000000..7f47ae39c --- /dev/null +++ b/native/connector/src/poll.c @@ -0,0 +1,416 @@ +/* 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; +} diff --git a/native/connector/src/pool.c b/native/connector/src/pool.c new file mode 100644 index 000000000..51c9159aa --- /dev/null +++ b/native/connector/src/pool.c @@ -0,0 +1,249 @@ +/* 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(); +} diff --git a/native/connector/src/proc.c b/native/connector/src/proc.c new file mode 100644 index 000000000..965f41dfb --- /dev/null +++ b/native/connector/src/proc.c @@ -0,0 +1,453 @@ +/* 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 +} diff --git a/native/connector/src/shm.c b/native/connector/src/shm.c new file mode 100644 index 000000000..82eb613bc --- /dev/null +++ b/native/connector/src/shm.c @@ -0,0 +1,126 @@ +/* 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; +} diff --git a/native/connector/src/ssl.c b/native/connector/src/ssl.c new file mode 100644 index 000000000..67a4bbf29 --- /dev/null +++ b/native/connector/src/ssl.c @@ -0,0 +1,809 @@ +/* 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 diff --git a/native/connector/src/sslcontext.c b/native/connector/src/sslcontext.c new file mode 100644 index 000000000..38a4772bb --- /dev/null +++ b/native/connector/src/sslcontext.c @@ -0,0 +1,571 @@ +/* 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 diff --git a/native/connector/src/sslinfo.c b/native/connector/src/sslinfo.c new file mode 100644 index 000000000..bf8dd2384 --- /dev/null +++ b/native/connector/src/sslinfo.c @@ -0,0 +1,562 @@ +/* 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 diff --git a/native/connector/src/sslnetwork.c b/native/connector/src/sslnetwork.c new file mode 100644 index 000000000..c7923721b --- /dev/null +++ b/native/connector/src/sslnetwork.c @@ -0,0 +1,528 @@ +/* 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 diff --git a/native/connector/src/sslutils.c b/native/connector/src/sslutils.c new file mode 100644 index 000000000..c875953b8 --- /dev/null +++ b/native/connector/src/sslutils.c @@ -0,0 +1,679 @@ +/* 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 diff --git a/native/connector/src/stdlib.c b/native/connector/src/stdlib.c new file mode 100644 index 000000000..59ac4600f --- /dev/null +++ b/native/connector/src/stdlib.c @@ -0,0 +1,119 @@ +/* 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; +} + diff --git a/native/connector/src/thread.c b/native/connector/src/thread.c new file mode 100644 index 000000000..53e1113af --- /dev/null +++ b/native/connector/src/thread.c @@ -0,0 +1,28 @@ +/* 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: 393735 $, $Date: 2006-04-13 08:41:49 +0200 (čet, 13 tra 2006) $ + */ + +#include "tcn.h" + +TCN_IMPLEMENT_CALL(jlong, Thread, current)(TCN_STDARGS) +{ + UNREFERENCED_STDARGS; + return (jlong)((unsigned long)apr_os_thread_current()); +} diff --git a/native/connector/src/user.c b/native/connector/src/user.c new file mode 100644 index 000000000..33713fd73 --- /dev/null +++ b/native/connector/src/user.c @@ -0,0 +1,162 @@ +/* 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; +} + diff --git a/native/connector/tcnative.dsp b/native/connector/tcnative.dsp new file mode 100644 index 000000000..5e5c46d81 --- /dev/null +++ b/native/connector/tcnative.dsp @@ -0,0 +1,231 @@ +# 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 diff --git a/native/connector/tcnative.pc.in b/native/connector/tcnative.pc.in new file mode 100644 index 000000000..f6ae98a22 --- /dev/null +++ b/native/connector/tcnative.pc.in @@ -0,0 +1,13 @@ +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}