Copy the tomcat-connector/jni/native to the native/connector.
authormturk <mturk@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 18 Oct 2006 11:09:50 +0000 (11:09 +0000)
committermturk <mturk@13f79535-47bb-0310-9956-ffa450edef68>
Wed, 18 Oct 2006 11:09:50 +0000 (11:09 +0000)
git-svn-id: https://svn.apache.org/repos/asf/tomcat/tc6.0.x/trunk@465208 13f79535-47bb-0310-9956-ffa450edef68

54 files changed:
native/connector/BUILDING [new file with mode: 0644]
native/connector/Makefile.in [new file with mode: 0644]
native/connector/build.conf [new file with mode: 0644]
native/connector/build/buildcheck.sh [new file with mode: 0644]
native/connector/build/get-version.sh [new file with mode: 0755]
native/connector/build/lineends.pl [new file with mode: 0644]
native/connector/build/mkdir.sh [new file with mode: 0644]
native/connector/build/rpm/tcnative.spec.in [new file with mode: 0644]
native/connector/build/tcnative.m4 [new file with mode: 0644]
native/connector/buildconf [new file with mode: 0755]
native/connector/config.layout [new file with mode: 0644]
native/connector/configure.in [new file with mode: 0644]
native/connector/include/ssl_private.h [new file with mode: 0644]
native/connector/include/tcn.h [new file with mode: 0644]
native/connector/include/tcn_api.h [new file with mode: 0644]
native/connector/include/tcn_version.h [new file with mode: 0644]
native/connector/libtcnative.dsp [new file with mode: 0644]
native/connector/libtcnative.dsw [new file with mode: 0644]
native/connector/os/netware/system.c [new file with mode: 0644]
native/connector/os/unix/system.c [new file with mode: 0644]
native/connector/os/unix/uxpipe.c [new file with mode: 0644]
native/connector/os/win32/apache.ico [new file with mode: 0644]
native/connector/os/win32/libtcnative.rc [new file with mode: 0644]
native/connector/os/win32/logmessages.bin [new file with mode: 0644]
native/connector/os/win32/logmessages.mc [new file with mode: 0644]
native/connector/os/win32/ntpipe.c [new file with mode: 0644]
native/connector/os/win32/registry.c [new file with mode: 0644]
native/connector/os/win32/system.c [new file with mode: 0644]
native/connector/src/address.c [new file with mode: 0644]
native/connector/src/dir.c [new file with mode: 0644]
native/connector/src/error.c [new file with mode: 0644]
native/connector/src/file.c [new file with mode: 0644]
native/connector/src/info.c [new file with mode: 0644]
native/connector/src/jnilib.c [new file with mode: 0644]
native/connector/src/lock.c [new file with mode: 0644]
native/connector/src/misc.c [new file with mode: 0644]
native/connector/src/mmap.c [new file with mode: 0644]
native/connector/src/multicast.c [new file with mode: 0644]
native/connector/src/network.c [new file with mode: 0644]
native/connector/src/os.c [new file with mode: 0644]
native/connector/src/poll.c [new file with mode: 0644]
native/connector/src/pool.c [new file with mode: 0644]
native/connector/src/proc.c [new file with mode: 0644]
native/connector/src/shm.c [new file with mode: 0644]
native/connector/src/ssl.c [new file with mode: 0644]
native/connector/src/sslcontext.c [new file with mode: 0644]
native/connector/src/sslinfo.c [new file with mode: 0644]
native/connector/src/sslnetwork.c [new file with mode: 0644]
native/connector/src/sslutils.c [new file with mode: 0644]
native/connector/src/stdlib.c [new file with mode: 0644]
native/connector/src/thread.c [new file with mode: 0644]
native/connector/src/user.c [new file with mode: 0644]
native/connector/tcnative.dsp [new file with mode: 0644]
native/connector/tcnative.pc.in [new file with mode: 0644]

diff --git a/native/connector/BUILDING b/native/connector/BUILDING
new file mode 100644 (file)
index 0000000..7f9e7b3
--- /dev/null
@@ -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 <Connector> use of conf/server.xml:
+    protocol="org.apache.coyote.http11.Http11AprProtocol"
+  2 - In bin/setenv.sh add the following: 
+    CATALINA_OPTS="$CATALINA_OPTS -Djava.library.path=tclib_location"
+    In my machine I am using:
+    /home/jfclere/tomcat-connectors/jni/native/.libs for tclib_location
+
+NOTES:
+  - configure --without-ssl : Configure without ssl support.
+  - To use it in Tomcat you may have to add in bin/setenv.sh:
+    LD_LIBRARY_PATH=openssl_install_location/lib; export LD_LIBRARY_PATH
+    (use ldd ./.libs/libtcnative-1.so to check it).
+  - quick testing: openssl s_client -connect localhost:8443
+  - For MAC OS X you must manually add a link
+    cd ${tcnative installdir}
+    ln -d libtcnative-1.dylib libtcnative-1.jnilib
diff --git a/native/connector/Makefile.in b/native/connector/Makefile.in
new file mode 100644 (file)
index 0000000..4e75af9
--- /dev/null
@@ -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 (file)
index 0000000..900ec4f
--- /dev/null
@@ -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 (file)
index 0000000..cd1d593
--- /dev/null
@@ -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 (executable)
index 0000000..fd685b2
--- /dev/null
@@ -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 (file)
index 0000000..f91a9d3
--- /dev/null
@@ -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 (file)
index 0000000..b947c92
--- /dev/null
@@ -0,0 +1,37 @@
+#!/bin/sh
+## 
+##  mkdir.sh -- make directory hierarchy
+##
+##  Based on `mkinstalldirs' from Noah Friedman <friedman@prep.ai.mit.edu>
+##  as of 1994-03-25, which was placed in the Public Domain.
+##  Cleaned up for Apache's Autoconf-style Interface (APACI)
+##  by Ralf S. Engelschall <rse@apache.org>
+##
+#
+# This script falls under the Apache License.
+# See http://www.apache.org/docs/LICENSE
+
+
+umask 022
+errstatus=0
+for file in ${1+"$@"} ; do 
+    set fnord `echo ":$file" |\
+               sed -e 's/^:\//%/' -e 's/^://' -e 's/\// /g' -e 's/^%/\//'`
+    shift
+    pathcomp=
+    for d in ${1+"$@"}; do
+        pathcomp="$pathcomp$d"
+        case "$pathcomp" in
+            -* ) pathcomp=./$pathcomp ;;
+            ?: ) pathcomp="$pathcomp/" 
+                 continue ;;
+        esac
+        if test ! -d "$pathcomp"; then
+            echo "mkdir $pathcomp" 1>&2
+            mkdir "$pathcomp" || errstatus=$?
+        fi
+        pathcomp="$pathcomp/"
+    done
+done
+exit $errstatus
+
diff --git a/native/connector/build/rpm/tcnative.spec.in b/native/connector/build/rpm/tcnative.spec.in
new file mode 100644 (file)
index 0000000..26969e8
--- /dev/null
@@ -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 <mturk@jboss.com> 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 (file)
index 0000000..c6f266f
--- /dev/null
@@ -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=<path>" if it was specified.
+dnl
+AC_DEFUN(TCN_CHECK_SSL_TOOLKIT,[
+  dnl initialise the variables we use
+  tcn_ssltk_base=""
+  tcn_ssltk_inc=""
+  tcn_ssltk_lib=""
+  tcn_ssltk_type=""
+  AC_ARG_WITH(ssl, TCN_HELP_STRING(--with-ssl=DIR,OpenSSL SSL/TLS toolkit), [
+    dnl If --with-ssl specifies a directory, we use that directory or fail
+    if test "x$withval" != "xyes" -a "x$withval" != "x"; then
+      dnl This ensures $withval is actually a directory and that it is absolute
+      tcn_ssltk_base="`cd $withval ; pwd`"
+    fi
+  ])
+  if test "x$tcn_ssltk_base" = "x"; then
+    AC_MSG_RESULT(none)
+  else
+    AC_MSG_RESULT($tcn_ssltk_base)
+  fi
+
+  dnl Run header and version checks
+  saved_CPPFLAGS=$CPPFLAGS
+  if test "x$tcn_ssltk_base" != "x"; then
+    tcn_ssltk_inc="-I$tcn_ssltk_base/include"
+    CPPFLAGS="$CPPFLAGS $tcn_ssltk_inc"
+  fi
+
+  if test "x$tcn_ssltk_type" = "x"; then
+    AC_MSG_CHECKING(for OpenSSL version)
+    dnl First check for manditory headers
+    AC_CHECK_HEADERS([openssl/opensslv.h], [tcn_ssltk_type="openssl"], [])
+    if test "$tcn_ssltk_type" = "openssl"; then
+      dnl so it's OpenSSL - test for a good version
+      AC_TRY_COMPILE([#include <openssl/opensslv.h>],[
+#if !defined(OPENSSL_VERSION_NUMBER)
+  #error "Missing openssl version"
+#endif
+#if  (OPENSSL_VERSION_NUMBER < 0x0090701f)
+  #error "Unsuported openssl version " OPENSSL_VERSION_TEXT
+#endif],
+      [AC_MSG_RESULT(OK)],
+      [dnl Unsuported OpenSSL version
+         AC_MSG_ERROR([Unsupported OpenSSL version. Use 0.9.7a or higher version])
+      ])
+      dnl Look for additional, possibly missing headers
+      AC_CHECK_HEADERS(openssl/engine.h)
+      if test -n "$PKGCONFIG"; then
+        $PKGCONFIG openssl
+        if test $? -eq 0; then
+          tcn_ssltk_inc="$tcn_ssltk_inc `$PKGCONFIG --cflags-only-I openssl`"
+          CPPFLAGS="$CPPFLAGS $tcn_ssltk_inc"
+        fi
+      fi
+    else
+      AC_MSG_RESULT([no OpenSSL headers found])
+    fi
+  fi
+  if test "$tcn_ssltk_type" != "openssl"; then
+    AC_MSG_ERROR([... No OpenSSL headers found])
+  fi
+  dnl restore
+  CPPFLAGS=$saved_CPPFLAGS
+  if test "x$tcn_ssltk_type" = "x"; then
+    AC_MSG_ERROR([...No recognized SSL/TLS toolkit detected])
+  fi
+
+  dnl Run library and function checks
+  saved_LDFLAGS=$LDFLAGS
+  saved_LIBS=$LIBS
+  if test "x$tcn_ssltk_base" != "x"; then
+    if test -d "$tcn_ssltk_base/lib64"; then
+      tcn_ssltk_lib="$tcn_ssltk_base/lib64"
+    elif test -d "$tcn_ssltk_base/lib"; then
+      tcn_ssltk_lib="$tcn_ssltk_base/lib"
+    else
+      tcn_ssltk_lib="$tcn_ssltk_base"
+    fi
+    LDFLAGS="$LDFLAGS -L$tcn_ssltk_lib"
+  fi
+  dnl make sure "other" flags are available so libcrypto and libssl can link
+  LIBS="$LIBS `$apr_config --libs`"
+  liberrors=""
+  if test "$tcn_ssltk_type" = "openssl"; then
+    AC_CHECK_LIB(crypto, SSLeay_version, [], [liberrors="yes"])
+    AC_CHECK_LIB(ssl, SSL_CTX_new, [], [liberrors="yes"])
+    AC_CHECK_FUNCS(ENGINE_init)
+    AC_CHECK_FUNCS(ENGINE_load_builtin_engines)
+  else
+    AC_CHECK_LIB(sslc, SSLC_library_version, [], [liberrors="yes"])
+    AC_CHECK_LIB(sslc, SSL_CTX_new, [], [liberrors="yes"])
+    AC_CHECK_FUNCS(SSL_set_state)
+  fi
+  AC_CHECK_FUNCS(SSL_set_cert_store)
+  dnl restore
+  LDFLAGS=$saved_LDFLAGS
+  LIBS=$saved_LIBS
+  if test "x$liberrors" != "x"; then
+    AC_MSG_ERROR([... Error, SSL/TLS libraries were missing or unusable])
+  fi
+
+  dnl (b) hook up include paths
+  if test "x$tcn_ssltk_inc" != "x"; then
+    APR_ADDTO(TCNATIVE_PRIV_INCLUDES, [$tcn_ssltk_inc])
+  fi
+  dnl (c) hook up linker paths
+  if test "x$tcn_ssltk_lib" != "x"; then
+    APR_ADDTO(TCNATIVE_LDFLAGS, ["-L$tcn_ssltk_lib"])
+  fi
+
+  dnl Adjust configuration based on what we found above.
+  dnl (a) define preprocessor symbols
+  if test "$tcn_ssltk_type" = "openssl"; then
+    APR_SETVAR(SSL_LIBS, [-lssl -lcrypto])
+    APR_ADDTO(CFLAGS, [-DHAVE_OPENSSL])
+  fi
+  AC_SUBST(SSL_LIBS)
+])
diff --git a/native/connector/buildconf b/native/connector/buildconf
new file mode 100755 (executable)
index 0000000..c5a1049
--- /dev/null
@@ -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 (file)
index 0000000..61422fc
--- /dev/null
@@ -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 
+##    `/<target>' suffix where <target> is currently hardcoded to 'apr'.
+##    (This may become a configurable parameter at some point.)
+##
+
+#   Generic path layout that needs --prefix=/some/path
+<Layout generic>
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/modules
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+    localstatedir: ${prefix}
+    libsuffix:     -${TCNATIVE_MAJOR_VERSION}
+</Layout>
+
+#   Classical Tomcat Native path layout designed for parallel installs.
+<Layout tcnative>
+    prefix:        /usr/local/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/modules
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+    localstatedir: ${prefix}
+    libsuffix:     -${TCNATIVE_MAJOR_VERSION}
+</Layout>
+
+#   Classical single-installation APR path layout.
+<Layout classic>
+    prefix:        /usr/local/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/modules
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include
+    localstatedir: ${prefix}
+</Layout>
+
+#   GNU standards conforming path layout.
+#   See FSF's GNU project `make-stds' document for details.
+<Layout GNU>
+    prefix:        /usr/local
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/etc+
+    datadir:       ${prefix}/share+
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include+
+    localstatedir: ${prefix}/var+
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#   Mac OS X Server (Rhapsody)
+<Layout Mac OS X Server>
+    prefix:        /Local/Library/WebServer
+    exec_prefix:   /usr
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    /System/Library/apr/Modules
+    mandir:        ${exec_prefix}/share/man
+    sysconfdir:    ${prefix}/Configuration
+    datadir:       ${prefix}
+    installbuilddir: /System/Library/apr/Build
+    includedir:    /System/Library/Frameworks/apr.framework/Versions/2.0/Headers
+    localstatedir: /var
+    runtimedir:    ${prefix}/Logs
+</Layout>
+
+#   Darwin/Mac OS Layout
+<Layout Darwin>
+    prefix:        /usr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec+
+    mandir:        ${prefix}/share/man
+    datadir:       /Library/WebServer
+    sysconfdir:    /etc+
+    installbuilddir: ${prefix}/share/httpd/build
+    includedir:    ${prefix}/include+
+    localstatedir: /var
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#   Red Hat Linux 7.x layout
+<Layout RedHat>
+    prefix:        /usr
+    exec_prefix:   ${prefix}
+    bindir:        ${prefix}/bin
+    sbindir:       ${prefix}/sbin
+    libdir:        ${prefix}/lib
+    libexecdir:    ${prefix}/lib/apr
+    mandir:        ${prefix}/man
+    sysconfdir:    /etc/httpd/conf
+    datadir:       /var/www
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include/apr
+    localstatedir: /var
+    runtimedir:    ${localstatedir}/run
+</Layout>     
+
+#   According to the /opt filesystem conventions
+<Layout opt>
+    prefix:        /opt/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${prefix}/man
+    sysconfdir:    /etc${prefix}
+    datadir:       ${prefix}/share
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include
+    localstatedir: /var${prefix}
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#  BeOS layout...
+<Layout beos>
+    prefix:        /boot/home/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include
+    localstatedir: ${prefix}
+    runtimedir:    ${localstatedir}/logs
+</Layout>
+
+#   SuSE 6.x layout
+<Layout SuSE>
+    prefix:        /usr
+    exec_prefix:   ${prefix}
+    bindir:        ${prefix}/bin
+    sbindir:       ${prefix}/sbin
+    libdir:        ${prefix}/lib
+    libexecdir:    ${prefix}/lib/apr
+    mandir:        ${prefix}/share/man
+    sysconfdir:    /etc/httpd
+    datadir:       /usr/local/httpd
+    installbuilddir: ${datadir}/build
+    includedir:    ${prefix}/include/apr
+    localstatedir: /var/lib/httpd
+    runtimedir:    /var/run
+</Layout>
+
+#   BSD/OS layout
+<Layout BSDI>
+    prefix:        /var/www
+    exec_prefix:   /usr/contrib
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec/apr
+    mandir:        ${exec_prefix}/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${datadir}/build
+    includedir:    ${exec_prefix}/include/apr
+    localstatedir: /var
+    runtimedir:    ${localstatedir}/run
+</Layout>
+
+#   Solaris 8 Layout
+<Layout Solaris>
+    prefix:        /usr/apr
+    exec_prefix:   ${prefix}
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/bin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/libexec
+    mandir:        ${exec_prefix}/man
+    sysconfdir:    /etc/apr
+    datadir:       /var/apr
+    installbuilddir: ${datadir}/build
+    includedir:    ${exec_prefix}/include
+    localstatedir: ${prefix}
+    runtimedir:    /var/run
+</Layout>
+
+#   OpenBSD Layout
+<Layout OpenBSD>
+    prefix:        /var/www
+    exec_prefix:   /usr
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/lib/apr/modules
+    mandir:        ${exec_prefix}/share/man
+    sysconfdir:    ${prefix}/conf
+    datadir:       ${prefix}
+    installbuilddir: ${prefix}/build
+    includedir:    ${exec_prefix}/lib/apr/include
+    localstatedir: ${prefix}
+    runtimedir:    ${prefix}/logs
+</Layout>
+
+# Debian layout
+<Layout Debian>
+    prefix:        
+    exec_prefix:   ${prefix}/usr
+    bindir:        ${exec_prefix}/bin
+    sbindir:       ${exec_prefix}/sbin
+    libdir:        ${exec_prefix}/lib
+    libexecdir:    ${exec_prefix}/lib/apr/modules
+    mandir:        ${exec_prefix}/share/man
+    datadir:       ${exec_prefix}/share/apr
+    includedir:    ${exec_prefix}/include/apr-${TCNATIVE_MAJOR_VERSION}
+    localstatedir: ${prefix}/var/run
+    runtimedir:    ${prefix}/var/run
+    infodir:       ${exec_prefix}/share/info
+    libsuffix     -${TCNATIVE_MAJOR_VERSION}
+    installbuilddir: ${prefix}/usr/share/apache2/build
+</Layout>
diff --git a/native/connector/configure.in b/native/connector/configure.in
new file mode 100644 (file)
index 0000000..0956d24
--- /dev/null
@@ -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 (file)
index 0000000..7ecfe28
--- /dev/null
@@ -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 <openssl/ssl.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include <openssl/pem.h>
+#include <openssl/crypto.h>
+#include <openssl/evp.h>
+#include <openssl/rand.h>
+#include <openssl/x509v3.h>
+#include <openssl/md5.h>
+/* Avoid tripping over an engine build installed globally and detected
+ * when the user points at an explicit non-engine flavor of OpenSSL
+ */
+#ifndef OPENSSL_NO_ENGINE
+#include <openssl/engine.h>
+#endif
+
+#ifndef RAND_MAX
+#include <limits.h>
+#define RAND_MAX INT_MAX
+#endif
+
+#define SSL_ALGO_UNKNOWN (0)
+#define SSL_ALGO_RSA     (1<<0)
+#define SSL_ALGO_DSA     (1<<1)
+#define SSL_ALGO_ALL     (SSL_ALGO_RSA|SSL_ALGO_DSA)
+
+#define SSL_AIDX_RSA     (0)
+#define SSL_AIDX_DSA     (1)
+#define SSL_AIDX_MAX     (2)
+
+/*
+ * Define IDs for the temporary RSA keys and DH params
+ */
+
+#define SSL_TMP_KEY_RSA_512     (0)
+#define SSL_TMP_KEY_RSA_1024    (1)
+#define SSL_TMP_KEY_RSA_2048    (2)
+#define SSL_TMP_KEY_RSA_4096    (3)
+#define SSL_TMP_KEY_DH_512      (4)
+#define SSL_TMP_KEY_DH_1024     (5)
+#define SSL_TMP_KEY_DH_2048     (6)
+#define SSL_TMP_KEY_DH_4096     (7)
+#define SSL_TMP_KEY_MAX         (8)
+
+#define SSL_CRT_FORMAT_UNDEF    (0)
+#define SSL_CRT_FORMAT_ASN1     (1)
+#define SSL_CRT_FORMAT_TEXT     (2)
+#define SSL_CRT_FORMAT_PEM      (3)
+#define SSL_CRT_FORMAT_NETSCAPE (4)
+#define SSL_CRT_FORMAT_PKCS12   (5)
+#define SSL_CRT_FORMAT_SMIME    (6)
+#define SSL_CRT_FORMAT_ENGINE   (7)
+/* XXX this stupid macro helps us to avoid
+ * adding yet another param to load_*key()
+ */
+#define SSL_KEY_FORMAT_IISSGC   (8)
+
+/*
+ * Define the SSL options
+ */
+#define SSL_OPT_NONE            (0)
+#define SSL_OPT_RELSET          (1<<0)
+#define SSL_OPT_STDENVVARS      (1<<1)
+#define SSL_OPT_EXPORTCERTDATA  (1<<3)
+#define SSL_OPT_FAKEBASICAUTH   (1<<4)
+#define SSL_OPT_STRICTREQUIRE   (1<<5)
+#define SSL_OPT_OPTRENEGOTIATE  (1<<6)
+#define SSL_OPT_ALL             (SSL_OPT_STDENVVARS|SSL_OPT_EXPORTCERTDATA|SSL_OPT_FAKEBASICAUTH|SSL_OPT_STRICTREQUIRE|SSL_OPT_OPTRENEGOTIATE)
+
+/*
+ * Define the SSL Protocol options
+ */
+#define SSL_PROTOCOL_NONE       (0)
+#define SSL_PROTOCOL_SSLV2      (1<<0)
+#define SSL_PROTOCOL_SSLV3      (1<<1)
+#define SSL_PROTOCOL_TLSV1      (1<<2)
+#define SSL_PROTOCOL_ALL        (SSL_PROTOCOL_SSLV2|SSL_PROTOCOL_SSLV3|SSL_PROTOCOL_TLSV1)
+
+#define SSL_MODE_CLIENT         (0)
+#define SSL_MODE_SERVER         (1)
+#define SSL_MODE_COMBINED       (2)
+
+#define SSL_BIO_FLAG_RDONLY     (1<<0)
+#define SSL_BIO_FLAG_CALLBACK   (1<<1)
+#define SSL_DEFAULT_CACHE_SIZE  (256)
+#define SSL_DEFAULT_VHOST_NAME  ("_default_:443")
+#define SSL_MAX_STR_LEN         (2048)
+#define SSL_MAX_PASSWORD_LEN    (256)
+
+#define SSL_CVERIFY_UNSET           (-1)
+#define SSL_CVERIFY_NONE            (0)
+#define SSL_CVERIFY_OPTIONAL        (1)
+#define SSL_CVERIFY_REQUIRE         (2)
+#define SSL_CVERIFY_OPTIONAL_NO_CA  (3)
+#define SSL_VERIFY_PEER_STRICT      (SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT)
+
+#define SSL_SHUTDOWN_TYPE_UNSET     (0)
+#define SSL_SHUTDOWN_TYPE_STANDARD  (1)
+#define SSL_SHUTDOWN_TYPE_UNCLEAN   (2)
+#define SSL_SHUTDOWN_TYPE_ACCURATE  (3)
+
+#define SSL_TO_APR_ERROR(X)         (APR_OS_START_USERERR + 1000 + X)
+
+#define SSL_INFO_SESSION_ID                 (0x0001)
+#define SSL_INFO_CIPHER                     (0x0002)
+#define SSL_INFO_CIPHER_USEKEYSIZE          (0x0003)
+#define SSL_INFO_CIPHER_ALGKEYSIZE          (0x0004)
+#define SSL_INFO_CIPHER_VERSION             (0x0005)
+#define SSL_INFO_CIPHER_DESCRIPTION         (0x0006)
+#define SSL_INFO_PROTOCOL                   (0x0007)
+
+#define SSL_INFO_CLIENT_S_DN                (0x0010)
+#define SSL_INFO_CLIENT_I_DN                (0x0020)
+#define SSL_INFO_SERVER_S_DN                (0x0040)
+#define SSL_INFO_SERVER_I_DN                (0x0080)
+
+#define SSL_INFO_DN_COUNTRYNAME             (0x0001)
+#define SSL_INFO_DN_STATEORPROVINCENAME     (0x0002)
+#define SSL_INFO_DN_LOCALITYNAME            (0x0003)
+#define SSL_INFO_DN_ORGANIZATIONNAME        (0x0004)
+#define SSL_INFO_DN_ORGANIZATIONALUNITNAME  (0x0005)
+#define SSL_INFO_DN_COMMONNAME              (0x0006)
+#define SSL_INFO_DN_TITLE                   (0x0007)
+#define SSL_INFO_DN_INITIALS                (0x0008)
+#define SSL_INFO_DN_GIVENNAME               (0x0009)
+#define SSL_INFO_DN_SURNAME                 (0x000A)
+#define SSL_INFO_DN_DESCRIPTION             (0x000B)
+#define SSL_INFO_DN_UNIQUEIDENTIFIER        (0x000C)
+#define SSL_INFO_DN_EMAILADDRESS            (0x000D)
+
+#define SSL_INFO_CLIENT_MASK                (0x0100)
+
+#define SSL_INFO_CLIENT_M_VERSION           (0x0101)
+#define SSL_INFO_CLIENT_M_SERIAL            (0x0102)
+#define SSL_INFO_CLIENT_V_START             (0x0103)
+#define SSL_INFO_CLIENT_V_END               (0x0104)
+#define SSL_INFO_CLIENT_A_SIG               (0x0105)
+#define SSL_INFO_CLIENT_A_KEY               (0x0106)
+#define SSL_INFO_CLIENT_CERT                (0x0107)
+#define SSL_INFO_CLIENT_V_REMAIN            (0x0108)
+
+#define SSL_INFO_SERVER_MASK                (0x0200)
+
+#define SSL_INFO_SERVER_M_VERSION           (0x0201)
+#define SSL_INFO_SERVER_M_SERIAL            (0x0202)
+#define SSL_INFO_SERVER_V_START             (0x0203)
+#define SSL_INFO_SERVER_V_END               (0x0204)
+#define SSL_INFO_SERVER_A_SIG               (0x0205)
+#define SSL_INFO_SERVER_A_KEY               (0x0206)
+#define SSL_INFO_SERVER_CERT                (0x0207)
+#define SSL_INFO_CLIENT_CERT_CHAIN          (0x0400)
+
+#define SSL_VERIFY_ERROR_IS_OPTIONAL(errnum) \
+   ((errnum == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) \
+    || (errnum == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN) \
+    || (errnum == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY) \
+    || (errnum == X509_V_ERR_CERT_UNTRUSTED) \
+    || (errnum == X509_V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE))
+
+
+
+#define SSL_DEFAULT_PASS_PROMPT "Some of your private key files are encrypted for security reasons.\n"  \
+                                "In order to read them you have to provide the pass phrases.\n"         \
+                                "Enter password :"
+
+extern void *SSL_temp_keys[SSL_TMP_KEY_MAX];
+
+typedef struct {
+    /* client can have any number of cert/key pairs */
+    const char  *cert_file;
+    const char  *cert_path;
+    STACK_OF(X509_INFO) *certs;
+} ssl_pkc_t;
+
+typedef struct tcn_ssl_ctxt_t tcn_ssl_ctxt_t;
+
+typedef struct {
+    char            password[SSL_MAX_PASSWORD_LEN];
+    const char     *prompt;
+    tcn_callback_t cb;
+} tcn_pass_cb_t;
+
+extern tcn_pass_cb_t tcn_password_callback;
+
+struct tcn_ssl_ctxt_t {
+    apr_pool_t      *pool;
+    SSL_CTX         *ctx;
+    BIO             *bio_os;
+    BIO             *bio_is;
+
+    unsigned char   context_id[MD5_DIGEST_LENGTH];
+
+    int             protocol;
+    /* we are one or the other */
+    int             mode;
+
+    /* certificate revocation list */
+    X509_STORE      *crl;
+    /* pointer to the context verify store */
+    X509_STORE      *store;
+    const char      *cert_files[SSL_AIDX_MAX];
+    const char      *key_files[SSL_AIDX_MAX];
+    X509            *certs[SSL_AIDX_MAX];
+    EVP_PKEY        *keys[SSL_AIDX_MAX];
+
+    int             ca_certs;
+    int             shutdown_type;
+    char            *rand_file;
+
+    const char      *cipher_suite;
+    /* for client or downstream server authentication */
+    int             verify_depth;
+    int             verify_mode;
+    tcn_pass_cb_t   *cb_data;
+};
+
+typedef struct {
+    apr_pool_t     *pool;
+    tcn_ssl_ctxt_t *ctx;
+    SSL            *ssl;
+    X509           *peer;
+    int             shutdown_type;
+    apr_socket_t   *sock;
+    apr_pollset_t  *pollset;
+} tcn_ssl_conn_t;
+
+
+#define SSL_CTX_get_extra_certs(ctx)        ((ctx)->extra_certs)
+#define SSL_CTX_set_extra_certs(ctx, value) \
+    TCN_BEGIN_MACRO                         \
+        (ctx)->extra_certs = (value);       \
+    TCN_END_MACRO
+
+/*
+ *  Additional Functions
+ */
+void        SSL_init_app_data2_idx(void);
+void       *SSL_get_app_data2(SSL *);
+void        SSL_set_app_data2(SSL *, void *);
+int         SSL_password_prompt(tcn_pass_cb_t *);
+int         SSL_password_callback(char *, int, int, void *);
+void        SSL_BIO_close(BIO *);
+void        SSL_BIO_doref(BIO *);
+DH         *SSL_dh_get_tmp_param(int);
+DH         *SSL_dh_get_param_from_file(const char *);
+RSA        *SSL_callback_tmp_RSA(SSL *, int, int);
+DH         *SSL_callback_tmp_DH(SSL *, int, int);
+void        SSL_vhost_algo_id(const unsigned char *, unsigned char *, int);
+int         SSL_CTX_use_certificate_chain(SSL_CTX *, const char *, int);
+int         SSL_callback_SSL_verify(int, X509_STORE_CTX *);
+int         SSL_rand_seed(const char *file);
+#endif /* SSL_PRIVATE_H */
diff --git a/native/connector/include/tcn.h b/native/connector/include/tcn.h
new file mode 100644 (file)
index 0000000..5cc4b85
--- /dev/null
@@ -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 <stdio.h>
+#include <stdlib.h>
+#if defined(_WIN32) && !defined(__CYGWIN__)
+#include <process.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "tcn_api.h"
+
+
+#if defined(_DEBUG) || defined(DEBUG)
+#include <assert.h>
+#define TCN_ASSERT(x)  assert((x))
+#else
+#define TCN_ASSERT(x) (void)0
+#endif
+
+#ifndef APR_MAX_IOVEC_SIZE
+#define APR_MAX_IOVEC_SIZE 1024
+#endif
+
+#define TCN_TIMEUP      APR_OS_START_USERERR + 1
+#define TCN_EAGAIN      APR_OS_START_USERERR + 2
+#define TCN_EINTR       APR_OS_START_USERERR + 3
+#define TCN_EINPROGRESS APR_OS_START_USERERR + 4
+#define TCN_ETIMEDOUT   APR_OS_START_USERERR + 5
+
+#define TCN_LOG_EMERG  1
+#define TCN_LOG_ERROR  2
+#define TCN_LOG_NOTICE 3
+#define TCN_LOG_WARN   4
+#define TCN_LOG_INFO   5
+#define TCN_LOG_DEBUG  6
+
+#define TCN_ERROR_WRAP(E)                   \
+    if (APR_STATUS_IS_TIMEUP(E))            \
+        (E) = TCN_TIMEUP;                   \
+    else if (APR_STATUS_IS_EAGAIN(E))       \
+        (E) = TCN_EAGAIN;                   \
+    else if (APR_STATUS_IS_EINTR(E))        \
+        (E) = TCN_EINTR;                    \
+    else if (APR_STATUS_IS_EINPROGRESS(E))  \
+        (E) = TCN_EINPROGRESS;              \
+    else if (APR_STATUS_IS_ETIMEDOUT(E))    \
+        (E) = TCN_ETIMEDOUT;                \
+    else                                    \
+        (E) = (E)
+
+#define TCN_CLASS_PATH  "org/apache/tomcat/jni/"
+#define TCN_FINFO_CLASS TCN_CLASS_PATH "FileInfo"
+#define TCN_AINFO_CLASS TCN_CLASS_PATH "Sockaddr"
+#define TCN_ERROR_CLASS TCN_CLASS_PATH "Error"
+#define TCN_PARENT_IDE  "TCN_PARENT_ID"
+
+#define UNREFERENCED(P)      (P) = (P)
+#define UNREFERENCED_STDARGS e = e; o = o
+#ifdef WIN32
+#define LLT(X) (X)
+#else
+#define LLT(X) ((long)(X))
+#endif
+#define P2J(P)          ((jlong)LLT(P))
+#define J2P(P, T)       ((T)LLT((jlong)P))
+/* On stack buffer size */
+#define TCN_BUFFER_SZ   8192
+#define TCN_STDARGS     JNIEnv *e, jobject o
+#define TCN_IMPARGS     JNIEnv *e, jobject o, void *sock
+#define TCN_IMPCALL(X)  e, o, X->opaque
+
+#define TCN_IMPLEMENT_CALL(RT, CL, FN)  \
+    JNIEXPORT RT JNICALL Java_org_apache_tomcat_jni_##CL##_##FN
+
+#define TCN_IMPLEMENT_METHOD(RT, FN)    \
+    static RT method_##FN
+
+#define TCN_GETNET_METHOD(FN)  method_##FN
+
+#define TCN_SOCKET_UNKNOWN  0
+#define TCN_SOCKET_APR      1
+#define TCN_SOCKET_SSL      2
+#define TCN_SOCKET_UNIX     3
+#define TCN_SOCKET_NTPIPE   4
+
+#define TCN_SOCKET_GET_POOL 0
+#define TCN_SOCKET_GET_IMPL 1
+#define TCN_SOCKET_GET_APRS 2
+#define TCN_SOCKET_GET_TYPE 3
+
+typedef struct {
+    int type;
+    apr_status_t (*cleanup)(void *);
+    apr_status_t (APR_THREAD_FUNC *close) (apr_socket_t *);
+    apr_status_t (APR_THREAD_FUNC *shutdown) (apr_socket_t *, apr_shutdown_how_e);
+    apr_status_t (APR_THREAD_FUNC *opt_get)(apr_socket_t *, apr_int32_t, apr_int32_t *);
+    apr_status_t (APR_THREAD_FUNC *opt_set)(apr_socket_t *, apr_int32_t, apr_int32_t);
+    apr_status_t (APR_THREAD_FUNC *timeout_get)(apr_socket_t *, apr_interval_time_t *);
+    apr_status_t (APR_THREAD_FUNC *timeout_set)(apr_socket_t *, apr_interval_time_t);
+    apr_status_t (APR_THREAD_FUNC *send) (apr_socket_t *, const char *, apr_size_t *);
+    apr_status_t (APR_THREAD_FUNC *sendv)(apr_socket_t *, const struct iovec *, apr_int32_t, apr_size_t *);
+    apr_status_t (APR_THREAD_FUNC *recv) (apr_socket_t *, char *, apr_size_t *);
+} tcn_nlayer_t;
+
+typedef struct {
+    apr_pool_t   *pool;
+    apr_socket_t *sock;
+    void         *opaque;
+    char         *jsbbuff;
+    char         *jrbbuff;
+    tcn_nlayer_t *net;
+} tcn_socket_t;
+
+/* Private helper functions */
+void            tcn_Throw(JNIEnv *, const char *, ...);
+void            tcn_ThrowException(JNIEnv *, const char *);
+void            tcn_ThrowMemoryException(JNIEnv *, const char *, int, const char *);
+void            tcn_ThrowAPRException(JNIEnv *, apr_status_t);
+jstring         tcn_new_string(JNIEnv *, const char *);
+jstring         tcn_new_stringn(JNIEnv *, const char *, size_t);
+jbyteArray      tcn_new_arrayb(JNIEnv *, const unsigned char *, size_t);
+jobjectArray    tcn_new_arrays(JNIEnv *env, size_t len);
+char           *tcn_get_string(JNIEnv *, jstring);
+char           *tcn_strdup(JNIEnv *, jstring);
+char           *tcn_pstrdup(JNIEnv *, jstring, apr_pool_t *);
+apr_status_t    tcn_load_finfo_class(JNIEnv *, jclass);
+apr_status_t    tcn_load_ainfo_class(JNIEnv *, jclass);
+
+#define J2S(V)  c##V
+#define J2L(V)  p##V
+
+#define J2T(T) (apr_time_t)((T))
+
+#define TCN_BEGIN_MACRO     if (1) {
+#define TCN_END_MACRO       } else (void)(0)
+
+#define TCN_ALLOC_CSTRING(V)     \
+    const char *c##V = V ? (const char *)((*e)->GetStringUTFChars(e, V, 0)) : NULL
+
+#define TCN_FREE_CSTRING(V)      \
+    if (c##V) (*e)->ReleaseStringUTFChars(e, V, c##V)
+
+#define TCN_ALLOC_JSTRING(V)     \
+    char *c##V = tcn_get_string(e, (V))
+
+#define AJP_TO_JSTRING(V)   (*e)->NewStringUTF((e), (V))
+
+#define TCN_FREE_JSTRING(V)      \
+    TCN_BEGIN_MACRO              \
+        if (c##V)                \
+            free(c##V);          \
+    TCN_END_MACRO
+
+#define TCN_CHECK_ALLOCATED(x)                              \
+        if (x == NULL) {                                    \
+            tcn_ThrowMemoryException(e, __FILE__, __LINE__, \
+            "APR memory allocation failed");                \
+            goto cleanup;                                   \
+        } else (void)(0)
+
+#define TCN_THROW_IF_ERR(x, r)                  \
+    TCN_BEGIN_MACRO                             \
+        apr_status_t R = (x);                   \
+        if (R != APR_SUCCESS) {                 \
+            tcn_ThrowAPRException(e, R);        \
+            (r) = 0;                            \
+            goto cleanup;                       \
+        }                                       \
+    TCN_END_MACRO
+
+#define TCN_THROW_OS_ERROR(E)   \
+    tcn_ThrowAPRException((E), apr_get_os_error())
+
+#define TCN_LOAD_CLASS(E, C, N, R)                  \
+    TCN_BEGIN_MACRO                                 \
+        jclass _##C = (*(E))->FindClass((E), N);    \
+        if (_##C == NULL) {                         \
+            (*(E))->ExceptionClear((E));            \
+            return R;                               \
+        }                                           \
+        C = (*(E))->NewGlobalRef((E), _##C);        \
+        (*(E))->DeleteLocalRef((E), _##C);          \
+    TCN_END_MACRO
+
+#define TCN_UNLOAD_CLASS(E, C)                      \
+        (*(E))->DeleteGlobalRef((E), (C))
+
+#define TCN_IS_NULL(E, O)                           \
+        ((*(E))->IsSameObject((E), (O), NULL) == JNI_TRUE)
+
+#define TCN_GET_METHOD(E, C, M, N, S, R)            \
+    TCN_BEGIN_MACRO                                 \
+        M = (*(E))->GetMethodID((E), C, N, S);      \
+        if (M == NULL) {                            \
+            return R;                               \
+        }                                           \
+    TCN_END_MACRO
+
+#define TCN_MAX_METHODS 8
+
+typedef struct {
+    jobject     obj;
+    jmethodID   mid[TCN_MAX_METHODS];
+    void        *opaque;
+} tcn_callback_t;
+
+#define TCN_MIN(a, b) ((a) < (b) ? (a) : (b))
+#define TCN_MAX(a, b) ((a) > (b) ? (a) : (b))
+
+#ifdef WIN32
+#define TCN_ALLOC_WSTRING(V)     \
+    jsize wl##V = (*e)->GetStringLength(e, V);   \
+    const jchar *ws##V = V ? (const jchar *)((*e)->GetStringChars(e, V, 0)) : NULL; \
+    jchar *w##V = NULL
+
+#define TCN_INIT_WSTRING(V)                                     \
+        w##V = (jchar *)malloc((wl##V + 1) * sizeof(jchar));    \
+        wcsncpy(w##V, ws##V, wl##V);                        \
+        w##V[wl##V] = 0
+
+#define TCN_FREE_WSTRING(V)      \
+    if (ws##V) (*e)->ReleaseStringChars(e, V, ws##V); \
+    if (ws##V) free (w##V)
+
+#define J2W(V)  w##V
+
+#endif
+
+#if  !APR_HAVE_IPV6
+#define APR_INET6 APR_INET
+#endif
+
+#define GET_S_FAMILY(T, F)           \
+    if (F == 0) T = APR_UNSPEC;      \
+    else if (F == 1) T = APR_INET;   \
+    else if (F == 2) T = APR_INET6;  \
+    else T = F
+
+#define GET_S_TYPE(T, F)             \
+    if (F == 0) T = SOCK_STREAM;     \
+    else if (F == 1) T = SOCK_DGRAM; \
+    else T = F
+
+#endif /* TCN_H */
diff --git a/native/connector/include/tcn_api.h b/native/connector/include/tcn_api.h
new file mode 100644 (file)
index 0000000..70dbb7b
--- /dev/null
@@ -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 <jni.h>
+
+/**
+ * TCN_DECLARE_EXPORT is defined when building the TCN dynamic library,
+ * so that all public symbols are exported.
+ *
+ * TCN_DECLARE_STATIC is defined when including the TCN public headers,
+ * to provide static linkage when the dynamic library may be unavailable.
+ *
+ * TCN_DECLARE_STATIC and TCN_DECLARE_EXPORT are left undefined when
+ * including the TCN public headers, to import and link the symbols from
+ * the dynamic TCN library and assure appropriate indirection and calling
+ * conventions at compile time.
+ */
+
+#if !defined(WIN32)
+/**
+ * The public TCN functions are declared with TCN_DECLARE(), so they may
+ * use the most appropriate calling convention.  Public APR functions with
+ * variable arguments must use TCN_DECLARE_NONSTD().
+ *
+ * @deffunc TCN_DECLARE(rettype) apr_func(args);
+ */
+#define TCN_DECLARE(type)            type
+/**
+ * The public TCN functions using variable arguments are declared with
+ * TCN_DECLARE_NONSTD(), as they must use the C language calling convention.
+ *
+ * @deffunc TCN_DECLARE_NONSTD(rettype) apr_func(args, ...);
+ */
+#define TCN_DECLARE_NONSTD(type)     type
+/**
+ * The public TCN variables are declared with TCN_DECLARE_DATA.
+ * This assures the appropriate indirection is invoked at compile time.
+ *
+ * @deffunc TCN_DECLARE_DATA type apr_variable;
+ * @tip extern TCN_DECLARE_DATA type apr_variable; syntax is required for
+ * declarations within headers to properly import the variable.
+ */
+#define TCN_DECLARE_DATA
+#elif defined(TCN_DECLARE_STATIC)
+#define TCN_DECLARE(type)            type __stdcall
+#define TCN_DECLARE_NONSTD(type)     type
+#define TCN_DECLARE_DATA
+#elif defined(TCN_DECLARE_EXPORT)
+#define TCN_DECLARE(type)            __declspec(dllexport) type __stdcall
+#define TCN_DECLARE_NONSTD(type)     __declspec(dllexport) type
+#define TCN_DECLARE_DATA             __declspec(dllexport)
+#else
+/**
+ * The public TCN functions are declared with TCN_DECLARE(), so they may
+ * use the most appropriate calling convention.  Public APR functions with
+ * variable arguments must use TCN_DECLARE_NONSTD().
+ *
+ */
+#define TCN_DECLARE(type)            __declspec(dllimport) type __stdcall
+/**
+ * The public TCN functions using variable arguments are declared with
+ * TCN_DECLARE_NONSTD(), as they must use the C language calling convention.
+ *
+ */
+#define TCN_DECLARE_NONSTD(type)     __declspec(dllimport) type
+/**
+ * The public TCN variables are declared with TCN_DECLARE_DATA.
+ * This assures the appropriate indirection is invoked at compile time.
+ *
+ * @remark extern TCN_DECLARE_DATA type apr_variable; syntax is required for
+ * declarations within headers to properly import the variable.
+ */
+#define TCN_DECLARE_DATA             __declspec(dllimport)
+#endif
+
+#if !defined(WIN32) || defined(TCN_MODULE_DECLARE_STATIC)
+/**
+ * Declare a dso module's exported module structure as TCN_MODULE_DECLARE_DATA.
+ *
+ * Unless TCN_MODULE_DECLARE_STATIC is defined at compile time, symbols
+ * declared with TCN_MODULE_DECLARE_DATA are always exported.
+ * @code
+ * module TCN_MODULE_DECLARE_DATA mod_tag
+ * @endcode
+ */
+#if defined(WIN32)
+#define TCN_MODULE_DECLARE(type)            type __stdcall
+#else
+#define TCN_MODULE_DECLARE(type)            type
+#endif
+#define TCN_MODULE_DECLARE_NONSTD(type)     type
+#define TCN_MODULE_DECLARE_DATA
+#else
+/**
+ * TCN_MODULE_DECLARE_EXPORT is a no-op.  Unless contradicted by the
+ * TCN_MODULE_DECLARE_STATIC compile-time symbol, it is assumed and defined.
+ */
+#define TCN_MODULE_DECLARE_EXPORT
+#define TCN_MODULE_DECLARE(type)          __declspec(dllexport) type __stdcall
+#define TCN_MODULE_DECLARE_NONSTD(type)   __declspec(dllexport) type
+#define TCN_MODULE_DECLARE_DATA           __declspec(dllexport)
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/**
+ * @file tcn_api.h
+ * @brief
+ *
+ * Tomcat Native Public API
+ */
+
+/* Return global apr pool
+ */
+TCN_DECLARE(apr_pool_t *) tcn_get_global_pool(void);
+
+/* Return global String class
+ */
+TCN_DECLARE(jclass) tcn_get_string_class(void);
+
+/* Return global JVM initalized on JNI_OnLoad
+ */
+TCN_DECLARE(JavaVM *) tcn_get_java_vm(void);
+
+/* Get current thread JNIEnv
+ */
+TCN_DECLARE(jint) tcn_get_java_env(JNIEnv **);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* TCN_API_H */
diff --git a/native/connector/include/tcn_version.h b/native/connector/include/tcn_version.h
new file mode 100644 (file)
index 0000000..9154d70
--- /dev/null
@@ -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 (file)
index 0000000..0e5d069
--- /dev/null
@@ -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 (file)
index 0000000..042257e
--- /dev/null
@@ -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 (file)
index 0000000..a770816
--- /dev/null
@@ -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 (file)
index 0000000..ba8cbb6
--- /dev/null
@@ -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 <sys/sysinfo.h>
+#elif defined(sun)
+#include <unistd.h>
+#include <sys/swap.h>
+#include <procfs.h>
+#include <kstat.h>
+#include <sys/sysinfo.h>
+#endif
+
+#if defined(DARWIN)
+#include <mach/mach_init.h>
+#include <mach/mach_host.h>
+#include <mach/host_info.h>
+#include <sys/sysctl.h>
+#include <sys/stat.h>
+#endif
+
+#include <syslog.h>
+#include <stdarg.h>
+
+#ifndef LOG_WARN
+#define LOG_WARN LOG_WARNING
+#endif
+
+#if defined(sun)
+#define MAX_PROC_PATH_LEN 64
+#define MAX_CPUS 512
+#define PSINFO_T_SZ sizeof(psinfo_t)
+#define PRUSAGE_T_SZ sizeof(prusage_t)
+
+static int proc_open(const char *type)
+{
+    char proc_path[MAX_PROC_PATH_LEN+1];
+
+    sprintf(proc_path, "/proc/self/%s", type);
+    return open(proc_path, O_RDONLY);
+}
+
+static int proc_read(void *buf, const size_t size, int filedes)
+{
+    ssize_t bytes;
+
+    if (filedes >= 0) {
+        bytes = pread(filedes, buf, size, 0);
+        if (bytes != size)
+            return -1;
+        else
+            return 0;
+    }
+    else
+        return -1;
+}
+
+#endif
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+    UNREFERENCED_STDARGS;
+    if (type == 1)
+        return JNI_TRUE;
+#if defined(__linux__)
+    else if (type == 5)
+        return JNI_TRUE;
+#endif
+#if defined(sun)
+    else if (type == 6)
+        return JNI_TRUE;
+#endif
+#if defined(__FreeBSD__) || defined(__NetBSD__)
+    else if (type == 7)
+        return JNI_TRUE;
+#endif
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+                                   jlongArray inf)
+{
+    jint rv;
+    int  i;
+    jsize ilen = (*e)->GetArrayLength(e, inf);
+    jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
+
+    UNREFERENCED(o);
+    if (ilen < 16) {
+        return APR_EINVAL;
+    }
+    for (i = 0; i < 16; i++)
+        pvals[i] = 0;
+#if defined(__linux__)
+    {
+        struct sysinfo info;
+        if (sysinfo(&info))
+            rv = apr_get_os_error();
+        else {
+            pvals[0] = (jlong)(info.totalram  * info.mem_unit);
+            pvals[1] = (jlong)(info.freeram   * info.mem_unit);
+            pvals[2] = (jlong)(info.totalswap * info.mem_unit);
+            pvals[3] = (jlong)(info.freeswap  * info.mem_unit);
+            pvals[4] = (jlong)(info.sharedram * info.mem_unit);
+            pvals[5] = (jlong)(info.bufferram * info.mem_unit);
+            pvals[6] = (jlong)(100 - (info.freeram * 100 / info.totalram));
+            rv = APR_SUCCESS;
+        }
+    }
+#elif defined(sun)
+    {
+        /* static variables with basic procfs info */
+        static long creation = 0;              /* unix timestamp of process creation */
+        static int psinf_fd = 0;               /* file descriptor for the psinfo procfs file */
+        static int prusg_fd = 0;               /* file descriptor for the usage procfs file */
+        static size_t rss = 0;                 /* maximum of resident set size from previous calls */
+        /* static variables with basic kstat info */
+        static kstat_ctl_t *kstat_ctl = NULL;  /* kstat control object, only initialized once */
+        static kstat_t *kstat_cpu[MAX_CPUS];   /* array of kstat objects for per cpu statistics */
+        static int cpu_count = 0;              /* number of cpu structures found in kstat */
+        static kid_t kid = 0;                  /* kstat ID, for which the kstat_ctl holds the correct chain */
+        /* non-static variables - general use */
+        int res = 0;                           /* general result state */
+        /* non-static variables - sysinfo/swapctl use */
+        long ret_sysconf;                      /* value returned from sysconf call */
+        long tck_dividend;                     /* factor used by transforming tick numbers to milliseconds */
+        long tck_divisor;                      /* divisor used by transforming tick numbers to milliseconds */
+        long sys_pagesize = sysconf(_SC_PAGESIZE); /* size of a system memory page in bytes */
+        long sys_clk_tck = sysconf(_SC_CLK_TCK); /* number of system ticks per second */
+        struct anoninfo info;                  /* structure for information about sizes in anonymous memory system */
+        /* non-static variables - procfs use */
+        psinfo_t psinf;                        /* psinfo structure from procfs */
+        prusage_t prusg;                       /* usage structure from procfs */
+        size_t new_rss = 0;                    /* resident set size read from procfs */
+        time_t now;                            /* time needed for calculating process creation time */
+        /* non-static variables - kstat use */
+        kstat_t *kstat = NULL;                 /* kstat working pointer */
+        cpu_sysinfo_t cpu;                     /* cpu sysinfo working pointer */
+        kid_t new_kid = 0;                     /* kstat ID returned from chain update */
+        int new_kstat = 0;                     /* flag indicating, if kstat structure has changed since last call */
+
+        rv = APR_SUCCESS;
+
+        if (sys_pagesize <= 0) {
+            rv = apr_get_os_error();
+        }
+        else {
+            ret_sysconf = sysconf(_SC_PHYS_PAGES);
+            if (ret_sysconf >= 0) {
+                pvals[0] = (jlong)((jlong)sys_pagesize * ret_sysconf);
+            }
+            else {
+                rv = apr_get_os_error();
+            }
+            ret_sysconf = sysconf(_SC_AVPHYS_PAGES);
+            if (ret_sysconf >= 0) {
+                pvals[1] = (jlong)((jlong)sys_pagesize * ret_sysconf);
+            }
+            else {
+                rv = apr_get_os_error();
+            }
+            res=swapctl(SC_AINFO, &info);
+            if (res >= 0) {
+                pvals[2] = (jlong)((jlong)sys_pagesize * info.ani_max);
+                pvals[3] = (jlong)((jlong)sys_pagesize * info.ani_free);
+                pvals[6] = (jlong)(100 - (jlong)info.ani_free * 100 / info.ani_max);
+            }
+            else {
+                rv = apr_get_os_error();
+            }
+        }
+
+        if (psinf_fd == 0) {
+            psinf_fd = proc_open("psinfo");
+        }
+        res = proc_read(&psinf, PSINFO_T_SZ, psinf_fd);
+        if (res >= 0) {
+            new_rss = psinf.pr_rssize*1024;
+            pvals[13] = (jlong)(new_rss);
+            if (new_rss > rss) {
+                rss = new_rss;
+            }
+            pvals[14] = (jlong)(rss);
+        }
+        else {
+            psinf_fd = 0;
+            rv = apr_get_os_error();
+        }
+        if (prusg_fd == 0) {
+            prusg_fd = proc_open("usage");
+        }
+        res = proc_read(&prusg, PRUSAGE_T_SZ, prusg_fd);
+        if (res >= 0) {
+            if (creation <= 0) {
+                time(&now);
+                creation = (long)(now - (prusg.pr_tstamp.tv_sec -
+                                         prusg.pr_create.tv_sec));
+            }
+            pvals[10] = (jlong)(creation);
+            pvals[11] = (jlong)((jlong)prusg.pr_stime.tv_sec * 1000 +
+                                (prusg.pr_stime.tv_nsec / 1000000));
+            pvals[12] = (jlong)((jlong)prusg.pr_utime.tv_sec * 1000 +
+                                (prusg.pr_utime.tv_nsec / 1000000));
+            pvals[15] = (jlong)(prusg.pr_majf);
+        }
+        else {
+            prusg_fd = 0;
+            rv = apr_get_os_error();
+        }
+
+        if (sys_clk_tck <= 0) {
+            rv = apr_get_os_error();
+        }
+        else {
+            tck_dividend = 1000;
+            tck_divisor = sys_clk_tck;
+            for (i = 0; i < 3; i++) {
+                if (tck_divisor % 2 == 0) {
+                    tck_divisor = tck_divisor / 2;
+                    tck_dividend = tck_dividend / 2;
+                }
+                if (tck_divisor % 5 == 0) {
+                    tck_divisor = tck_divisor / 5;
+                    tck_dividend = tck_dividend / 5;
+                }
+            }
+            if (kstat_ctl == NULL) {
+                kstat_ctl = kstat_open();
+                kid = kstat_ctl->kc_chain_id;
+                new_kstat = 1;
+            } else {
+                new_kid = kstat_chain_update(kstat_ctl);
+                if (new_kid < 0) {
+                    res=kstat_close(kstat_ctl);
+                    kstat_ctl = kstat_open();
+                    kid = kstat_ctl->kc_chain_id;
+                    new_kstat = 1;
+                } else if (new_kid > 0 && kid != new_kid) {
+                    kid = new_kid;
+                    new_kstat = 1;
+                }
+            }
+            if (new_kstat) {
+                cpu_count = 0;
+                for (kstat = kstat_ctl->kc_chain; kstat; kstat = kstat->ks_next) {
+                    if (strncmp(kstat->ks_name, "cpu_stat", 8) == 0) {
+                        kstat_cpu[cpu_count++]=kstat;
+                    }
+                }
+            }
+            for (i = 0; i < cpu_count; i++) {
+                new_kid = kstat_read(kstat_ctl, kstat_cpu[i], NULL);
+                if (new_kid >= 0) {
+                    cpu = ((cpu_stat_t *)kstat_cpu[i]->ks_data)->cpu_sysinfo;
+                    if ( tck_divisor == 1 ) {
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend);
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend);
+                        pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend);
+                        pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend);
+                    } else {
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_IDLE]) * tck_dividend / tck_divisor);
+                        pvals[7] += (jlong)(((jlong)cpu.cpu[CPU_WAIT]) * tck_dividend / tck_divisor);
+                        pvals[8] += (jlong)(((jlong)cpu.cpu[CPU_KERNEL]) * tck_dividend / tck_divisor);
+                        pvals[9] += (jlong)(((jlong)cpu.cpu[CPU_USER]) * tck_dividend / tck_divisor);
+                    }
+                }
+            }
+        }
+
+        /*
+         * The next two are not implemented yet for Solaris
+         * inf[4]  - Amount of shared memory
+         * inf[5]  - Memory used by buffers
+         *
+         */
+    }
+
+#elif defined(DARWIN)
+
+    uint64_t mem_total;
+    size_t len = sizeof(mem_total);
+
+    vm_statistics_data_t vm_info;
+    mach_msg_type_number_t info_count = HOST_VM_INFO_COUNT;
+
+    sysctlbyname("hw.memsize", &mem_total, &len, NULL, 0);
+    pvals[0] = (jlong)mem_total;
+
+    host_statistics(mach_host_self (), HOST_VM_INFO, (host_info_t)&vm_info, &info_count);
+    pvals[1] = (jlong)(((double)vm_info.free_count)*vm_page_size);
+    pvals[6] = (jlong)(100 - (pvals[1] * 100 / mem_total));
+    rv = APR_SUCCESS;
+
+/* DARWIN */
+#else
+    rv = APR_ENOTIMPL;
+#endif
+   (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+    return rv;
+}
+
+#define LOG_MSG_DOMAIN                   "Native"
+
+
+TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
+{
+    jstring str;
+    TCN_ALLOC_CSTRING(val);
+
+    UNREFERENCED(o);
+
+    /* TODO: Make ${ENVAR} expansion */
+    str = (*e)->NewStringUTF(e, J2S(val));
+
+    TCN_FREE_CSTRING(val);
+    return str;
+}
+
+TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
+{
+    const char *d;
+    TCN_ALLOC_CSTRING(domain);
+
+    UNREFERENCED(o);
+    if ((d = J2S(domain)) == NULL)
+        d = LOG_MSG_DOMAIN;
+
+    openlog(d, LOG_CONS | LOG_PID, LOG_LOCAL0);
+    TCN_FREE_CSTRING(domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
+                                     jstring msg)
+{
+    TCN_ALLOC_CSTRING(msg);
+    int id = LOG_DEBUG;
+    UNREFERENCED(o);
+
+    switch (level) {
+        case TCN_LOG_EMERG:
+            id = LOG_EMERG;
+        break;
+        case TCN_LOG_ERROR:
+            id = LOG_ERR;
+        break;
+        case TCN_LOG_NOTICE:
+            id = LOG_NOTICE;
+        break;
+        case TCN_LOG_WARN:
+            id = LOG_WARN;
+        break;
+        case TCN_LOG_INFO:
+            id = LOG_INFO;
+        break;
+    }
+    syslog (id, "%s", J2S(msg));
+
+    TCN_FREE_CSTRING(msg);
+}
diff --git a/native/connector/os/unix/uxpipe.c b/native/connector/os/unix/uxpipe.c
new file mode 100644 (file)
index 0000000..19a5798
--- /dev/null
@@ -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 <sys/stat.h>
+#include <sys/un.h> /* for sockaddr_un */
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t uxp_created  = 0;
+static volatile apr_uint32_t uxp_closed   = 0;
+static volatile apr_uint32_t uxp_cleared  = 0;
+static volatile apr_uint32_t uxp_accepted = 0;
+
+void uxp_network_dump_statistics()
+{
+    fprintf(stderr, "NT Network Statistics ..\n");
+    fprintf(stderr, "Sockets created         : %d\n", uxp_created);
+    fprintf(stderr, "Sockets accepted        : %d\n", uxp_accepted);
+    fprintf(stderr, "Sockets closed          : %d\n", uxp_closed);
+    fprintf(stderr, "Sockets cleared         : %d\n", uxp_cleared);
+}
+
+#endif
+
+#define DEFNAME     "/var/run/tomcatnativesock"
+#define DEFNAME_FMT "/var/run/tomcatnativesock%08x%08x"
+#define DEFSIZE     8192
+#define DEFTIMEOUT  60000
+
+#define TCN_UXP_UNKNOWN     0
+#define TCN_UXP_CLIENT      1
+#define TCN_UXP_ACCEPTED    2
+#define TCN_UXP_SERVER      3
+
+#define TCN_UNIX_MAXPATH    1024
+typedef struct {
+    apr_pool_t          *pool;
+    apr_socket_t        *sock;               /* APR socket */
+    int                 sd;
+    struct sockaddr_un  uxaddr;
+    int                 timeout;
+    int                 mode;                 /* Client or server mode */
+    char                name[TCN_UNIX_MAXPATH+1];
+} tcn_uxp_conn_t;
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    if (t < 0)
+        con->timeout = -1;
+    else
+        con->timeout = (int)(apr_time_as_msec(t));
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t*)sock;
+    if (con->timeout < 0)
+        *t = -1;
+    else
+        *t = con->timeout * 1000;
+    return APR_SUCCESS;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+uxp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_opt_set(con->sock, opt, on);
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+uxp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_opt_get(con->sock, opt, on);
+}
+
+static apr_status_t uxp_cleanup(void *data)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)data;
+
+    if (con) {
+        if (con->sock) {
+            apr_socket_close(con->sock);
+            con->sock = NULL;
+        }
+        if (con->mode == TCN_UXP_SERVER) {
+            unlink(con->name);
+            con->mode = TCN_UXP_UNKNOWN;
+        }
+    }
+
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&uxp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_shutdown(con->sock, how);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_close(apr_socket_t *sock)
+{
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&uxp_closed);
+#endif
+    return uxp_cleanup(sock);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_recv(con->sock, buf, len);
+}
+
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_send(apr_socket_t *sock, const char *buf,
+                apr_size_t *len)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_send(con->sock, buf, len);
+}
+
+static apr_status_t APR_THREAD_FUNC
+uxp_socket_sendv(apr_socket_t *sock,
+                 const struct iovec *vec,
+                 apr_int32_t nvec, apr_size_t *len)
+{
+    tcn_uxp_conn_t *con = (tcn_uxp_conn_t *)sock;
+    return apr_socket_sendv(con->sock, vec, nvec, len);
+}
+
+static apr_status_t uxp_socket_cleanup(void *data)
+{
+    tcn_socket_t *s = (tcn_socket_t *)data;
+
+    if (s->net->cleanup) {
+        (*s->net->cleanup)(s->opaque);
+        s->net->cleanup = NULL;
+    }
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&uxp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static tcn_nlayer_t uxp_socket_layer = {
+    TCN_SOCKET_UNIX,
+    uxp_cleanup,
+    uxp_socket_close,
+    uxp_socket_shutdown,
+    uxp_socket_opt_get,
+    uxp_socket_opt_set,
+    uxp_socket_timeout_get,
+    uxp_socket_timeout_set,
+    uxp_socket_send,
+    uxp_socket_sendv,
+    uxp_socket_recv
+};
+
+TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name,
+                                         jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_socket_t   *s   = NULL;
+    tcn_uxp_conn_t *con = NULL;
+    int sd;
+    TCN_ALLOC_CSTRING(name);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if ((sd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+        tcn_ThrowAPRException(e, apr_get_netos_error());
+        return 0;
+    }
+#ifdef TCN_DO_STATISTICS
+    uxp_created++;
+#endif
+    con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t));
+    con->pool = p;
+    con->mode = TCN_UXP_UNKNOWN;
+    con->timeout = DEFTIMEOUT;
+    con->sd = sd;
+    con->uxaddr.sun_family = AF_UNIX;
+    if (J2S(name)) {
+        strcpy(con->uxaddr.sun_path, J2S(name));
+        TCN_FREE_CSTRING(name);
+    }
+    else
+        strcpy(con->uxaddr.sun_path, DEFNAME);
+    s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+    s->pool   = p;
+    s->net    = &uxp_socket_layer;
+    s->opaque = con;
+    apr_pool_cleanup_register(p, (const void *)s,
+                              uxp_socket_cleanup,
+                              apr_pool_cleanup_null);
+
+    apr_os_sock_put(&(con->sock), &(con->sd), p);
+
+    return P2J(s);
+
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock,
+                                      jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_UNIX) {
+        int rc;
+        tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+        c->mode = TCN_UXP_SERVER;
+        rc = bind(c->sd, (struct sockaddr *)&(c->uxaddr), sizeof(c->uxaddr));
+        if (rc < 0)
+            return errno;
+        else
+            return APR_SUCCESS;
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock,
+                                        jint backlog)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_UNIX) {
+        tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+        c->mode = TCN_UXP_SERVER;
+        return apr_socket_listen(c->sock, (apr_int32_t)backlog);
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = NULL;
+    tcn_socket_t *a = NULL;
+    tcn_uxp_conn_t *con = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+    if (s->net->type == TCN_SOCKET_UNIX) {
+        apr_socklen_t len;
+        tcn_uxp_conn_t *c = (tcn_uxp_conn_t *)s->opaque;
+        con = (tcn_uxp_conn_t *)apr_pcalloc(p, sizeof(tcn_uxp_conn_t));
+        con->pool = p;
+        con->mode = TCN_UXP_ACCEPTED;
+        con->timeout = c->timeout;
+        len = sizeof(c->uxaddr);
+        /* Block until a client connects */
+        con->sd = accept(c->sd, (struct sockaddr *)&(con->uxaddr), &len);
+        if (con->sd < 0) {
+            tcn_ThrowAPRException(e, apr_get_os_error());
+            goto cleanup;
+        }
+    }
+    else {
+        tcn_ThrowAPRException(e, APR_ENOTIMPL);
+        goto cleanup;
+    }
+    if (con) {
+#ifdef TCN_DO_STATISTICS
+        apr_atomic_inc32(&uxp_accepted);
+#endif
+        a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+        a->pool   = p;
+           a->net    = &uxp_socket_layer;
+        a->opaque = con;
+        apr_pool_cleanup_register(p, (const void *)a,
+                                  uxp_socket_cleanup,
+                                  apr_pool_cleanup_null);
+        apr_os_sock_put(&(con->sock), &(con->sd), p);
+    }
+    return P2J(a);
+cleanup:
+    if (p)
+        apr_pool_destroy(p);
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock,
+                                         jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    tcn_uxp_conn_t *con = NULL;
+    int rc;
+
+    UNREFERENCED(o);
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type != TCN_SOCKET_UNIX)
+        return APR_ENOTSOCK;
+    con = (tcn_uxp_conn_t *)s->opaque;
+    if (con->mode != TCN_UXP_UNKNOWN)
+        return APR_EINVAL;
+    do {
+        rc = connect(con->sd, (const struct sockaddr *)&(con->uxaddr),
+                     sizeof(con->uxaddr));
+    } while (rc == -1 && errno == EINTR);
+
+    if (rc == -1 && errno != EISCONN)
+        return errno;
+    con->mode = TCN_UXP_CLIENT;
+
+    return APR_SUCCESS;
+}
diff --git a/native/connector/os/win32/apache.ico b/native/connector/os/win32/apache.ico
new file mode 100644 (file)
index 0000000..bfb4f63
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 (file)
index 0000000..e239e12
--- /dev/null
@@ -0,0 +1,69 @@
+#include <windows.h>
+
+LANGUAGE 0x9,0x1
+1 11 logmessages.bin
+
+#define TCN_COPYRIGHT "Copyright 2000-2006 The Apache Software " \
+                      "Foundation or its licensors, as applicable."
+
+#define TCN_LICENSE "Licensed under the Apache License, Version 2.0 " \
+                    "(the ""License""); you may not use this file except " \
+                    "in compliance with the License.  You may obtain a " \
+                    "copy of the License at\r\n\r\n" \
+                    "http://www.apache.org/licenses/LICENSE-2.0\r\n\r\n" \
+                    "Unless required by applicable law or agreed to in " \
+                    "writing, software distributed under the License is " \
+                    "distributed on an ""AS IS"" BASIS, WITHOUT " \
+                    "WARRANTIES OR CONDITIONS OF ANY KIND, either " \
+                    "express or implied.  See the License for the " \
+                    "specific language governing permissions and " \
+                    "limitations under the License."
+
+#define TCN_VERISON "1.1.6"
+1000 ICON "apache.ico"
+
+1001 DIALOGEX 0, 0, 252, 51
+STYLE DS_SETFONT | DS_MODALFRAME | DS_FIXEDSYS | DS_CENTER | WS_CAPTION
+CAPTION "Password prompt"
+FONT 8, "MS Shell Dlg", 0, 0, 0x0
+BEGIN
+    ICON            1000,-1,8,6,21,20
+    LTEXT           "Some of your private key files are encrypted for security reasons.\nIn order to read them you have to provide the pass phrases.",
+                    -1,29,5,220,19
+    LTEXT           "Enter password:",-1,7,28,75,8
+    EDITTEXT        1002,67,27,174,12,ES_PASSWORD | ES_AUTOHSCROLL
+END
+
+1 VERSIONINFO
+ FILEVERSION 1,1,6,0
+ PRODUCTVERSION 1,1,6,0
+ FILEFLAGSMASK 0x3fL
+#ifdef _DEBUG
+ FILEFLAGS 0x1L
+#else
+ FILEFLAGS 0x0L
+#endif
+ FILEOS 0x40004L
+ FILETYPE 0x1L
+ FILESUBTYPE 0x0L
+BEGIN
+    BLOCK "StringFileInfo"
+    BEGIN
+        BLOCK "040904b0"
+        BEGIN
+            VALUE "Comments",  TCN_LICENSE "\0"
+            VALUE "CompanyName", "Apache Software Foundation\0"
+            VALUE "FileDescription", "Tomcat Native Java Library\0"
+            VALUE "FileVersion", TCN_VERISON "\0"
+            VALUE "InternalName", "libtcnative-1\0"
+            VALUE "LegalCopyright", TCN_COPYRIGHT "\0"
+            VALUE "OriginalFilename", "libtcnative-1.dll\0"
+            VALUE "ProductName", "Tomcat Native Java Library\0"
+            VALUE "ProductVersion", TCN_VERISON "\0"
+        END
+    END
+    BLOCK "VarFileInfo"
+    BEGIN
+        VALUE "Translation", 0x409, 1200
+    END
+END
diff --git a/native/connector/os/win32/logmessages.bin b/native/connector/os/win32/logmessages.bin
new file mode 100644 (file)
index 0000000..44ce985
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 (file)
index 0000000..68f86f6
--- /dev/null
@@ -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 (file)
index 0000000..2c40f31
--- /dev/null
@@ -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 <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <sddl.h>
+
+#include "tcn.h"
+#include "apr_thread_mutex.h"
+#include "apr_poll.h"
+
+#ifdef TCN_DO_STATISTICS
+#include "apr_atomic.h"
+
+static volatile apr_uint32_t ntp_created  = 0;
+static volatile apr_uint32_t ntp_closed   = 0;
+static volatile apr_uint32_t ntp_cleared  = 0;
+static volatile apr_uint32_t ntp_accepted = 0;
+
+void ntp_network_dump_statistics()
+{
+    fprintf(stderr, "NT Network Statistics ..\n");
+    fprintf(stderr, "Sockets created         : %d\n", ntp_created);
+    fprintf(stderr, "Sockets accepted        : %d\n", ntp_accepted);
+    fprintf(stderr, "Sockets closed          : %d\n", ntp_closed);
+    fprintf(stderr, "Sockets cleared         : %d\n", ntp_cleared);
+}
+
+#endif
+
+#define DEFNAME     "\\\\.\\PIPE\\TOMCATNATIVEPIPE"
+#define DEFNAME_FMT "\\\\.\\PIPE\\TOMCATNATIVEPIPE%08X%08X"
+#define DEFSIZE     8192
+#define DEFTIMEOUT  60000
+
+#define TCN_NTP_UNKNOWN 0
+#define TCN_NTP_CLIENT  1
+#define TCN_NTP_SERVER  2
+
+typedef struct {
+    apr_pool_t     *pool;
+    apr_socket_t   *sock;               /* Dummy socket */
+    OVERLAPPED     rd_o;
+    OVERLAPPED     wr_o;
+    HANDLE         h_pipe;
+    HANDLE         rd_event;
+    HANDLE         wr_event;
+    DWORD          timeout;
+    int            mode;                 /* Client or server mode */
+    int            nmax;
+    DWORD          sndbuf;
+    DWORD          rcvbuf;
+    char           name[MAX_PATH+1];
+    SECURITY_ATTRIBUTES sa;
+} tcn_ntp_conn_t;
+
+static const char *NTSD_STRING = "D:"     /* Discretionary ACL */
+                   "(D;OICI;GA;;;BG)"     /* Deny access to Built-in Guests */
+                   "(D;OICI;GA;;;AN)"     /* Deny access to Anonymous Logon */
+                   "(A;OICI;GRGWGX;;;AU)" /* Allow read/write/execute to Authenticated Users */
+                   "(A;OICI;GA;;;BA)"     /* Allow full control to Administrators */
+                   "(A;OICI;GA;;;LS)"     /* Allow full control to Local service account */
+                   "(A;OICI;GA;;;SY)";    /* Allow full control to Local system */
+
+
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_timeout_set(apr_socket_t *sock, apr_interval_time_t t)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    if (t < 0)
+        con->timeout = INFINITE;
+    else
+        con->timeout = (DWORD)(apr_time_as_msec(t));
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_timeout_get(apr_socket_t *sock, apr_interval_time_t *t)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t*)sock;
+    if (con->timeout == INFINITE)
+        *t = -1;
+    else
+        *t = con->timeout * 1000;
+    return APR_SUCCESS;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ntp_socket_opt_set(apr_socket_t *sock, apr_int32_t opt, apr_int32_t on)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    apr_status_t rv = APR_SUCCESS;
+    switch (opt) {
+        case APR_SO_SNDBUF:
+            con->sndbuf = (DWORD)on;
+        break;
+        case APR_SO_RCVBUF:
+            con->rcvbuf = (DWORD)on;
+        break;
+        default:
+            rv = APR_EINVAL;
+        break;
+    }
+    return rv;
+}
+
+static APR_INLINE apr_status_t APR_THREAD_FUNC
+ntp_socket_opt_get(apr_socket_t *sock, apr_int32_t opt, apr_int32_t *on)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    apr_status_t rv = APR_SUCCESS;
+    switch (opt) {
+        case APR_SO_SNDBUF:
+            *on = con->sndbuf;
+        break;
+        case APR_SO_RCVBUF:
+            *on = con->rcvbuf;
+        break;
+        default:
+            rv = APR_EINVAL;
+        break;
+    }
+    return rv;
+}
+
+static apr_status_t ntp_cleanup(void *data)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)data;
+
+    if (con) {
+        if (con->h_pipe) {
+            FlushFileBuffers(con->h_pipe);
+            CloseHandle(con->h_pipe);
+            con->h_pipe = NULL;
+        }
+        if (con->rd_event) {
+            CloseHandle(con->rd_event);
+            con->rd_event = NULL;
+        }
+        if (con->wr_event) {
+            CloseHandle(con->wr_event);
+            con->wr_event= NULL;
+        }
+    }
+
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ntp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_shutdown(apr_socket_t *sock, apr_shutdown_how_e how)
+{
+    UNREFERENCED(how);
+    return ntp_cleanup(sock);;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_close(apr_socket_t *sock)
+{
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ntp_closed);
+#endif
+    return ntp_cleanup(sock);;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_recv(apr_socket_t *sock, char *buf, apr_size_t *len)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    DWORD readed;
+
+    if (!ReadFile(con->h_pipe, buf, *len, &readed, &con->rd_o)) {
+        DWORD err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            DWORD r = WaitForSingleObject(con->rd_event, con->timeout);
+            if (r == WAIT_TIMEOUT)
+                return APR_TIMEUP;
+            else if (r != WAIT_OBJECT_0)
+                return APR_EOF;
+        }
+        else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) {
+            /* Server closed the pipe */
+            return APR_EOF;
+        }
+        GetOverlappedResult(con->h_pipe, &con->rd_o, &readed, FALSE);
+    }
+    *len = readed;
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_send(apr_socket_t *sock, const char *buf,
+                apr_size_t *len)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    DWORD written;
+
+    if (!WriteFile(con->h_pipe, buf, *len, &written, &con->wr_o)) {
+        DWORD err = GetLastError();
+        if (err == ERROR_IO_PENDING) {
+            DWORD r = WaitForSingleObject(con->wr_event, con->timeout);
+            if (r == WAIT_TIMEOUT)
+                return APR_TIMEUP;
+            else if (r != WAIT_OBJECT_0)
+                return APR_EOF;
+        }
+        else if (err == ERROR_BROKEN_PIPE || err == ERROR_NO_DATA) {
+            /* Server closed the pipe */
+            return APR_EOF;
+        }
+        GetOverlappedResult(con->h_pipe, &con->wr_o, &written, FALSE);
+    }
+    *len = written;
+    return APR_SUCCESS;
+}
+
+static apr_status_t APR_THREAD_FUNC
+ntp_socket_sendv(apr_socket_t *sock,
+                 const struct iovec *vec,
+                 apr_int32_t nvec, apr_size_t *len)
+{
+    tcn_ntp_conn_t *con = (tcn_ntp_conn_t *)sock;
+    apr_status_t rv;
+    apr_size_t written = 0;
+    apr_int32_t i;
+
+    for (i = 0; i < nvec; i++) {
+        apr_size_t rd = vec[i].iov_len;
+        if ((rv = ntp_socket_send((apr_socket_t *)con,
+                                  vec[i].iov_base, &rd)) != APR_SUCCESS) {
+            *len = written;
+            return rv;
+        }
+        written += rd;
+    }
+    *len = written;
+    return APR_SUCCESS;
+}
+
+static apr_status_t ntp_socket_cleanup(void *data)
+{
+    tcn_socket_t *s = (tcn_socket_t *)data;
+
+    if (s->net->cleanup) {
+        (*s->net->cleanup)(s->opaque);
+        s->net->cleanup = NULL;
+    }
+#ifdef TCN_DO_STATISTICS
+    apr_atomic_inc32(&ntp_cleared);
+#endif
+    return APR_SUCCESS;
+}
+
+static tcn_nlayer_t ntp_socket_layer = {
+    TCN_SOCKET_NTPIPE,
+    ntp_cleanup,
+    ntp_socket_close,
+    ntp_socket_shutdown,
+    ntp_socket_opt_get,
+    ntp_socket_opt_set,
+    ntp_socket_timeout_get,
+    ntp_socket_timeout_set,
+    ntp_socket_send,
+    ntp_socket_sendv,
+    ntp_socket_recv
+};
+
+static BOOL create_DACL(LPSECURITY_ATTRIBUTES psa)
+{
+
+    return ConvertStringSecurityDescriptorToSecurityDescriptor(
+                NTSD_STRING,
+                SDDL_REVISION_1,
+                &(psa->lpSecurityDescriptor),
+                NULL);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, create)(TCN_STDARGS, jstring name,
+                                         jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_socket_t   *s   = NULL;
+    tcn_ntp_conn_t *con = NULL;
+    TCN_ALLOC_CSTRING(name);
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+#ifdef TCN_DO_STATISTICS
+    ntp_created++;
+#endif
+    con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t));
+    con->pool = p;
+    con->mode = TCN_NTP_UNKNOWN;
+    con->nmax = PIPE_UNLIMITED_INSTANCES;
+    con->timeout = DEFTIMEOUT;
+    con->sndbuf  = DEFSIZE;
+    con->rcvbuf  = DEFSIZE;
+    if (J2S(name)) {
+        strncpy(con->name, J2S(name), MAX_PATH);
+        con->name[MAX_PATH] = '\0';
+        TCN_FREE_CSTRING(name);
+    }
+    else
+        strcpy(con->name, DEFNAME);
+    con->sa.nLength = sizeof(con->sa);
+    con->sa.bInheritHandle = TRUE;
+    if (!create_DACL(&con->sa)) {
+        tcn_ThrowAPRException(e, apr_get_os_error());
+        return 0;
+    }
+
+    s = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+    s->pool   = p;
+    s->net    = &ntp_socket_layer;
+    s->opaque = con;
+    apr_pool_cleanup_register(p, (const void *)s,
+                              ntp_socket_cleanup,
+                              apr_pool_cleanup_null);
+
+    fflush(stderr);
+    return P2J(s);
+
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, bind)(TCN_STDARGS, jlong sock,
+                                      jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_NTPIPE) {
+        tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+        c->mode = TCN_NTP_SERVER;
+        return APR_SUCCESS;
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, listen)(TCN_STDARGS, jlong sock,
+                                        jint backlog)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    UNREFERENCED_STDARGS;
+
+    TCN_ASSERT(sock != 0);
+    if (s->net->type == TCN_SOCKET_NTPIPE) {
+        tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+        c->mode = TCN_NTP_SERVER;
+        if (backlog > 0)
+            c->nmax = backlog;
+        else
+            c->nmax = PIPE_UNLIMITED_INSTANCES;
+        return APR_SUCCESS;
+    }
+    else
+        return APR_EINVAL;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Local, accept)(TCN_STDARGS, jlong sock)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = NULL;
+    tcn_socket_t *a = NULL;
+    tcn_ntp_conn_t *con = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(sock != 0);
+
+    TCN_THROW_IF_ERR(apr_pool_create(&p, s->pool), p);
+    if (s->net->type == TCN_SOCKET_NTPIPE) {
+        tcn_ntp_conn_t *c = (tcn_ntp_conn_t *)s->opaque;
+        con = (tcn_ntp_conn_t *)apr_pcalloc(p, sizeof(tcn_ntp_conn_t));
+        con->pool = p;
+        con->mode = TCN_NTP_SERVER;
+        con->nmax = c->nmax;
+        con->timeout = c->timeout;
+        strcpy(con->name, c->name);
+        con->h_pipe = CreateNamedPipe(con->name,
+                                      PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED,
+                                      PIPE_TYPE_BYTE | PIPE_READMODE_BYTE | PIPE_WAIT,
+                                      con->nmax,
+                                      con->sndbuf,
+                                      con->rcvbuf,
+                                      con->timeout,
+                                      &c->sa);
+        if (con->h_pipe == INVALID_HANDLE_VALUE) {
+            tcn_ThrowAPRException(e, apr_get_os_error());
+            goto cleanup;
+        }
+        /* Block until a client connects */
+        if (!ConnectNamedPipe(con->h_pipe, NULL)) {
+            DWORD err = GetLastError();
+            if (err != ERROR_PIPE_CONNECTED) {
+                CloseHandle(con->h_pipe);
+                tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(err));
+                goto cleanup;
+            }
+        }
+        /* Create overlapped events */
+        con->rd_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+        con->rd_o.hEvent = con->rd_event;
+        con->wr_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+        con->wr_o.hEvent = con->wr_event;
+    }
+    else {
+        tcn_ThrowAPRException(e, APR_ENOTIMPL);
+        goto cleanup;
+    }
+    if (con) {
+#ifdef TCN_DO_STATISTICS
+        apr_atomic_inc32(&ntp_accepted);
+#endif
+        a = (tcn_socket_t *)apr_pcalloc(p, sizeof(tcn_socket_t));
+        a->pool   = p;
+        a->net    = &ntp_socket_layer;
+        a->opaque = con;
+        apr_pool_cleanup_register(p, (const void *)a,
+                                  ntp_socket_cleanup,
+                                  apr_pool_cleanup_null);
+    }
+    return P2J(a);
+cleanup:
+    if (p)
+        apr_pool_destroy(p);
+    return 0;
+}
+
+TCN_IMPLEMENT_CALL(jint, Local, connect)(TCN_STDARGS, jlong sock,
+                                         jlong sa)
+{
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);
+    apr_pool_t   *p = NULL;
+    tcn_socket_t *a = NULL;
+    tcn_ntp_conn_t *con = NULL;
+
+    UNREFERENCED(o);
+    UNREFERENCED(sa);
+    TCN_ASSERT(sock != 0);
+    if (s->net->type != TCN_SOCKET_NTPIPE)
+        return APR_ENOTSOCK;
+    con = (tcn_ntp_conn_t *)s->opaque;
+    if (con->mode == TCN_NTP_SERVER)
+        return APR_EINVAL;
+    con->mode = TCN_NTP_CLIENT;
+
+    while (TRUE) {
+        con->h_pipe = CreateFile(con->name,
+                                 GENERIC_WRITE | GENERIC_READ,
+                                 FILE_SHARE_READ | FILE_SHARE_WRITE ,
+                                 NULL,
+                                 OPEN_EXISTING,
+                                 FILE_FLAG_OVERLAPPED,
+                                 NULL);
+        if (con->h_pipe != INVALID_HANDLE_VALUE)
+            break;
+        if (GetLastError() == ERROR_PIPE_BUSY) {
+            /* All pipe instances are busy, so wait for
+             * timeout value specified by the server process in
+             * the CreateNamedPipe function.
+             */
+            if (!WaitNamedPipe(con->name, NMPWAIT_USE_DEFAULT_WAIT))
+                return apr_get_os_error();
+        }
+        else
+            return apr_get_os_error();
+    }
+
+    /* Create overlapped events */
+    con->rd_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+    con->rd_o.hEvent = con->rd_event;
+    con->wr_event    = CreateEvent(NULL, TRUE, FALSE, NULL);
+    con->wr_o.hEvent = con->wr_event;
+
+    return APR_SUCCESS;
+}
diff --git a/native/connector/os/win32/registry.c b/native/connector/os/win32/registry.c
new file mode 100644 (file)
index 0000000..32fcd43
--- /dev/null
@@ -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 <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include <shlwapi.h>
+
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_arch_misc.h"   /* for apr_os_level */
+#include "apr_arch_atime.h"  /* for FileTimeToAprTime */
+
+#include "tcn.h"
+
+#define SAFE_CLOSE_KEY(k)                               \
+    if ((k) != NULL && (k) != INVALID_HANDLE_VALUE) {   \
+        RegCloseKey((k));                               \
+        (k) = NULL;                                     \
+    }
+
+typedef struct {
+    apr_pool_t     *pool;
+    HKEY           root;
+    HKEY           key;
+} tcn_nt_registry_t;
+
+
+#define TCN_HKEY_CLASSES_ROOT       1
+#define TCN_HKEY_CURRENT_CONFIG     2
+#define TCN_HKEY_CURRENT_USER       3
+#define TCN_HKEY_LOCAL_MACHINE      4
+#define TCN_HKEY_USERS              5
+
+static const struct {
+    HKEY k;
+} TCN_KEYS[] = {
+    INVALID_HANDLE_VALUE,
+    HKEY_CLASSES_ROOT,
+    HKEY_CURRENT_CONFIG,
+    HKEY_CURRENT_USER,
+    HKEY_LOCAL_MACHINE,
+    HKEY_USERS,
+    INVALID_HANDLE_VALUE
+};
+
+#define TCN_KEY_ALL_ACCESS          0x0001
+#define TCN_KEY_CREATE_LINK         0x0002
+#define TCN_KEY_CREATE_SUB_KEY      0x0004
+#define TCN_KEY_ENUMERATE_SUB_KEYS  0x0008
+#define TCN_KEY_EXECUTE             0x0010
+#define TCN_KEY_NOTIFY              0x0020
+#define TCN_KEY_QUERY_VALUE         0x0040
+#define TCN_KEY_READ                0x0080
+#define TCN_KEY_SET_VALUE           0x0100
+#define TCN_KEY_WOW64_64KEY         0x0200
+#define TCN_KEY_WOW64_32KEY         0x0400
+#define TCN_KEY_WRITE               0x0800
+
+#define TCN_REGSAM(s, x)                    \
+        s = 0;                              \
+        if (x & TCN_KEY_ALL_ACCESS)         \
+            s |= KEY_ALL_ACCESS;            \
+        if (x & TCN_KEY_CREATE_LINK)        \
+            s |= KEY_CREATE_LINK;           \
+        if (x & TCN_KEY_CREATE_SUB_KEY)     \
+            s |= KEY_CREATE_SUB_KEY;        \
+        if (x & TCN_KEY_ENUMERATE_SUB_KEYS) \
+            s |= KEY_ENUMERATE_SUB_KEYS;    \
+        if (x & TCN_KEY_EXECUTE)            \
+            s |= KEY_EXECUTE;               \
+        if (x & TCN_KEY_NOTIFY)             \
+            s |= KEY_NOTIFY;                \
+        if (x & TCN_KEY_READ)               \
+            s |= KEY_READ;                  \
+        if (x & TCN_KEY_SET_VALUE)          \
+            s |= KEY_SET_VALUE;             \
+        if (x & TCN_KEY_WOW64_64KEY)        \
+            s |= KEY_WOW64_64KEY;           \
+        if (x & TCN_KEY_WOW64_32KEY)        \
+            s |= KEY_WOW64_32KEY;           \
+        if (x & TCN_KEY_WRITE)              \
+            s |= KEY_WRITE
+
+#define TCN_REG_BINARY              1
+#define TCN_REG_DWORD               2
+#define TCN_REG_EXPAND_SZ           3
+#define TCN_REG_MULTI_SZ            4
+#define TCN_REG_QWORD               5
+#define TCN_REG_SZ                  6
+
+static const struct {
+    DWORD t;
+} TCN_REGTYPES[] = {
+    REG_NONE,
+    REG_BINARY,
+    REG_DWORD,
+    REG_EXPAND_SZ,
+    REG_MULTI_SZ,
+    REG_QWORD,
+    REG_SZ,
+    REG_NONE
+};
+
+static apr_status_t registry_cleanup(void *data)
+{
+    tcn_nt_registry_t *reg = (tcn_nt_registry_t *)data;
+
+    if (reg) {
+        SAFE_CLOSE_KEY(reg->key);
+    }
+    return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, create)(TCN_STDARGS, jint root, jstring name,
+                                            jint sam, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_nt_registry_t *reg = NULL;
+    TCN_ALLOC_WSTRING(name);
+    HKEY key;
+    LONG rc;
+    REGSAM s;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+        tcn_ThrowException(e, "Invalid Registry Root Key");
+        goto cleanup;
+    }
+    if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
+        tcn_ThrowException(e, "Invalid Registry Key Security");
+        goto cleanup;
+    }
+    reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
+    reg->pool = p;
+    reg->root = TCN_KEYS[root].k;
+    reg->key  = NULL;
+    TCN_INIT_WSTRING(name);
+    TCN_REGSAM(s, sam);
+    rc = RegCreateKeyExW(reg->root, J2W(name), 0, NULL, REG_OPTION_NON_VOLATILE,
+                         s, NULL, &key, NULL);
+    if (rc !=  ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    reg->key = key;
+    apr_pool_cleanup_register(p, (const void *)reg,
+                              registry_cleanup,
+                              apr_pool_cleanup_null);
+
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return P2J(reg);
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, open)(TCN_STDARGS, jint root, jstring name,
+                                          jint sam, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    tcn_nt_registry_t *reg = NULL;
+    TCN_ALLOC_WSTRING(name);
+    HKEY key;
+    LONG rc;
+    REGSAM s;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(pool != 0);
+
+    if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+        tcn_ThrowException(e, "Invalid Registry Root Key");
+        goto cleanup;
+    }
+    if (sam < TCN_KEY_ALL_ACCESS || root > TCN_KEY_WRITE) {
+        tcn_ThrowException(e, "Invalid Registry Key Security");
+        goto cleanup;
+    }
+    reg = (tcn_nt_registry_t *)apr_palloc(p, sizeof(tcn_nt_registry_t));
+    reg->pool = p;
+    reg->root = TCN_KEYS[root].k;
+    reg->key  = NULL;
+    TCN_INIT_WSTRING(name);
+    TCN_REGSAM(s, sam);
+    rc = RegOpenKeyExW(reg->root, J2W(name), 0, s, &key);
+    if (rc !=  ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    reg->key = key;
+    apr_pool_cleanup_register(p, (const void *)reg,
+                              registry_cleanup,
+                              apr_pool_cleanup_null);
+
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return P2J(reg);
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, close)(TCN_STDARGS, jlong reg)
+{
+    tcn_nt_registry_t *r = J2P(reg, tcn_nt_registry_t *);
+    UNREFERENCED_STDARGS;
+
+    TCN_ASSERT(reg != 0);
+
+    registry_cleanup(r);
+    apr_pool_cleanup_kill(r->pool, r, registry_cleanup);
+    return APR_SUCCESS;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getType)(TCN_STDARGS, jlong key,
+                                            jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD v;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &v, NULL, NULL);
+    if (rc != ERROR_SUCCESS)
+        v = -rc;
+    TCN_FREE_WSTRING(name);
+    switch (v) {
+        case REG_BINARY:
+            v = TCN_REG_BINARY;
+            break;
+        case REG_DWORD:
+            v = TCN_REG_DWORD;
+            break;
+        case REG_EXPAND_SZ:
+            v = TCN_REG_EXPAND_SZ;
+            break;
+        case REG_MULTI_SZ:
+            v = TCN_REG_MULTI_SZ;
+            break;
+        case REG_QWORD:
+            v = TCN_REG_QWORD;
+            break;
+        case REG_SZ:
+            v = TCN_REG_SZ;
+            break;
+        case REG_DWORD_BIG_ENDIAN:
+            v = 0;
+            break;
+    }
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getSize)(TCN_STDARGS, jlong key,
+                                            jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD v;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, NULL, &v);
+    if (rc != ERROR_SUCCESS)
+        v = -rc;
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, getValueI)(TCN_STDARGS, jlong key,
+                                              jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    DWORD v = 0;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_DWORD) {
+        l = sizeof(DWORD);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            goto cleanup;
+        }
+    }
+    else if (t == REG_SZ || t == REG_BINARY ||
+             t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
+        v = l;
+    else {
+        v = 0;
+        tcn_ThrowException(e, "Unable to convert the value to integer");
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jlong, Registry, getValueJ)(TCN_STDARGS, jlong key,
+                                               jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    UINT64 v = 0;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_DWORD) {
+        DWORD tv;
+        l = sizeof(DWORD);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&tv, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            goto cleanup;
+        }
+        v = tv;
+    }
+    else if (t == REG_QWORD) {
+        l = sizeof(UINT64);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)&v, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            goto cleanup;
+        }
+    }
+    else if (t == REG_SZ || t == REG_BINARY ||
+             t == REG_MULTI_SZ || t == REG_EXPAND_SZ)
+        v = l;
+    else {
+        v = 0;
+        tcn_ThrowException(e, "Unable to convert the value to long");
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jstring, Registry, getValueS)(TCN_STDARGS, jlong key,
+                                                 jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    jstring v = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_SZ || t == REG_EXPAND_SZ) {
+        jchar *vw = (jchar *)malloc(l);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            free(vw);
+            goto cleanup;
+        }
+        v = (*e)->NewString((e), vw, wcslen(vw));
+        free(vw);
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jbyteArray, Registry, getValueB)(TCN_STDARGS, jlong key,
+                                                    jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    jbyteArray v = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_BINARY) {
+        BYTE *b = (BYTE *)malloc(l);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, b, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            free(b);
+            goto cleanup;
+        }
+        v = tcn_new_arrayb(e, b, l);
+        free(b);
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+static jsize get_multi_sz_count(LPCWSTR str)
+{
+    LPCWSTR p = str;
+    jsize   cnt = 0;
+    for ( ; p && *p; p++) {
+        cnt++;
+        while (*p)
+            p++;
+    }
+    return cnt;
+}
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, getValueA)(TCN_STDARGS, jlong key,
+                                                      jstring name)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD t, l;
+    jobjectArray v = NULL;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegQueryValueExW(k->key, J2W(name), NULL, &t, NULL, &l);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    if (t == REG_MULTI_SZ) {
+        jsize cnt = 0;
+        jchar *p;
+        jchar *vw = (jchar *)malloc(l);
+        rc = RegQueryValueExW(k->key, J2W(name), NULL, NULL, (LPBYTE)vw, &l);
+        if (rc != ERROR_SUCCESS) {
+            tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+            free(vw);
+            goto cleanup;
+        }
+        cnt = get_multi_sz_count(vw);
+        if (cnt) {
+            jsize idx = 0;
+            v = tcn_new_arrays(e, cnt);
+            for (p = vw ; p && *p; p++) {
+                jstring s;
+                jchar *b = p;
+                while (*p)
+                    p++;
+                s = (*e)->NewString((e), b, (jsize)(p - b));
+                (*e)->SetObjectArrayElement((e), v, idx++, s);
+            }
+        }
+        free(vw);
+    }
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueI)(TCN_STDARGS, jlong key,
+                                              jstring name, jint val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    DWORD v = (DWORD)val;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_DWORD, (CONST BYTE *)&v, sizeof(DWORD));
+    TCN_FREE_WSTRING(name);
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueJ)(TCN_STDARGS, jlong key,
+                                              jstring name, jlong val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    UINT64 v = (UINT64)val;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_QWORD, (CONST BYTE *)&v, sizeof(UINT64));
+    TCN_FREE_WSTRING(name);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueS)(TCN_STDARGS, jlong key,
+                                              jstring name, jstring val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    TCN_ALLOC_WSTRING(val);
+    LONG rc;
+    DWORD len;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    TCN_INIT_WSTRING(val);
+    len = wcslen(J2W(val));
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_SZ,
+                        (CONST BYTE *)J2W(val), (len + 1) * 2);
+    TCN_FREE_WSTRING(name);
+    TCN_FREE_WSTRING(val);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueE)(TCN_STDARGS, jlong key,
+                                              jstring name, jstring val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    TCN_ALLOC_WSTRING(val);
+    LONG rc;
+    DWORD len;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    TCN_INIT_WSTRING(val);
+    len = wcslen(J2W(val));
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_EXPAND_SZ,
+                        (CONST BYTE *)J2W(val), (len + 1) * 2);
+    TCN_FREE_WSTRING(name);
+    TCN_FREE_WSTRING(val);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueA)(TCN_STDARGS, jlong key,
+                                              jstring name,
+                                              jobjectArray vals)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    LONG rc;
+    jsize i, len;
+    jsize sl = 0;
+    jchar *msz, *p;
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    TCN_INIT_WSTRING(name);
+    len = (*e)->GetArrayLength((e), vals);
+    for (i = 0; i < len; i++) {
+        jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
+        sl += (*e)->GetStringLength((e), s) + 1;
+    }
+    sl = (sl + 1) * 2;
+    p = msz = (jchar *)calloc(1, sl);
+    for (i = 0; i < len; i++) {
+        jsize   l;
+        jstring s = (jstring)(*e)->GetObjectArrayElement((e), vals, i);
+        l = (*e)->GetStringLength((e), s);
+        wcsncpy(p, (*e)->GetStringChars(e, s, 0), l);
+        p += l + 1;
+    }
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_MULTI_SZ,
+                        (CONST BYTE *)msz, sl);
+    TCN_FREE_WSTRING(name);
+    free(msz);
+    return rc;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, setValueB)(TCN_STDARGS, jlong key,
+                                              jstring name,
+                                              jbyteArray val)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    TCN_ALLOC_WSTRING(name);
+    jsize nbytes = (*e)->GetArrayLength(e, val);
+    jbyte *bytes = (*e)->GetByteArrayElements(e, val, NULL);
+    LONG rc;
+
+    rc = RegSetValueExW(k->key, J2W(name), 0, REG_BINARY,
+                        bytes, (DWORD)nbytes);
+    (*e)->ReleaseByteArrayElements(e, val, bytes, JNI_ABORT);
+    TCN_FREE_WSTRING(name);
+    return rc;
+}
+
+#define MAX_VALUE_NAME 4096
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumKeys)(TCN_STDARGS, jlong key)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    LONG rc;
+    jobjectArray v = NULL;
+    jsize cnt = 0;
+
+    WCHAR    achKey[MAX_PATH];
+    WCHAR    achClass[MAX_PATH] = L"";
+    DWORD    cchClassName = MAX_PATH;
+    DWORD    cSubKeys;
+    DWORD    cbMaxSubKey;
+    DWORD    cchMaxClass;
+    DWORD    cValues;
+    DWORD    cchMaxValue;
+    DWORD    cbMaxValueData;
+    DWORD    cbSecurityDescriptor;
+    FILETIME ftLastWriteTime;
+
+    DWORD cchValue = MAX_VALUE_NAME;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    rc = RegQueryInfoKeyW(k->key,
+                          achClass,
+                          &cchClassName,
+                          NULL,
+                          &cSubKeys,
+                          &cbMaxSubKey,
+                          &cchMaxClass,
+                          &cValues,
+                          &cchMaxValue,
+                          &cbMaxValueData,
+                          &cbSecurityDescriptor,
+                          &ftLastWriteTime);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    cnt = cSubKeys;
+    if (cnt) {
+        jsize idx = 0;
+        v = tcn_new_arrays(e, cnt);
+        for (idx = 0; idx < cnt; idx++) {
+            jstring s;
+            DWORD achKeyLen = MAX_PATH;
+            rc = RegEnumKeyExW(k->key,
+                               idx,
+                               achKey,
+                               &achKeyLen,
+                               NULL,
+                               NULL,
+                               NULL,
+                               &ftLastWriteTime);
+            if (rc == (DWORD)ERROR_SUCCESS) {
+                s = (*e)->NewString((e), achKey, wcslen(achKey));
+                (*e)->SetObjectArrayElement((e), v, idx, s);
+            }
+        }
+    }
+cleanup:
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jobjectArray, Registry, enumValues)(TCN_STDARGS, jlong key)
+{
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+    LONG rc;
+    jobjectArray v = NULL;
+    jsize cnt = 0;
+
+    WCHAR    achClass[MAX_PATH] = L"";
+    DWORD    cchClassName = MAX_PATH;
+    DWORD    cSubKeys;
+    DWORD    cbMaxSubKey;
+    DWORD    cchMaxClass;
+    DWORD    cValues;
+    DWORD    cchMaxValue;
+    DWORD    cbMaxValueData;
+    DWORD    cbSecurityDescriptor;
+    FILETIME ftLastWriteTime;
+
+    WCHAR  achValue[MAX_VALUE_NAME];
+    DWORD  cchValue = MAX_VALUE_NAME;
+
+    UNREFERENCED(o);
+    TCN_ASSERT(key != 0);
+    /* Get the class name and the value count. */
+    rc = RegQueryInfoKeyW(k->key,
+                          achClass,
+                          &cchClassName,
+                          NULL,
+                          &cSubKeys,
+                          &cbMaxSubKey,
+                          &cchMaxClass,
+                          &cValues,
+                          &cchMaxValue,
+                          &cbMaxValueData,
+                          &cbSecurityDescriptor,
+                          &ftLastWriteTime);
+    if (rc != ERROR_SUCCESS) {
+        tcn_ThrowAPRException(e, APR_FROM_OS_ERROR(rc));
+        goto cleanup;
+    }
+    cnt = cValues;
+    if (cnt) {
+        jsize idx = 0;
+        v = tcn_new_arrays(e, cnt);
+        for (idx = 0; idx < cnt; idx++) {
+            jstring s;
+            cchValue = MAX_VALUE_NAME;
+            achValue[0] = '\0';
+            rc = RegEnumValueW(k->key, idx,
+                               achValue,
+                               &cchValue,
+                               NULL,
+                               NULL,    // &dwType,
+                               NULL,    // &bData,
+                               NULL);   // &bcData
+            if (rc == (DWORD)ERROR_SUCCESS) {
+                s = (*e)->NewString((e), achValue, wcslen(achValue));
+                (*e)->SetObjectArrayElement((e), v, idx, s);
+            }
+        }
+    }
+cleanup:
+    return v;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, deleteKey)(TCN_STDARGS, jint root, jstring name,
+                                              jboolean only_if_empty)
+{
+    DWORD rv;
+    TCN_ALLOC_WSTRING(name);
+
+    UNREFERENCED(o);
+    if (root < TCN_HKEY_CLASSES_ROOT || root > TCN_HKEY_USERS) {
+        rv = EBADF;
+        goto cleanup;
+    }
+    if (only_if_empty)
+        rv = SHDeleteEmptyKeyW(TCN_KEYS[root].k, J2W(name));
+    else
+        rv = SHDeleteKeyW(TCN_KEYS[root].k, J2W(name));
+cleanup:
+    TCN_FREE_WSTRING(name);
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jint, Registry, deleteValue)(TCN_STDARGS, jlong key,
+                                                jstring name)
+{
+    LONG rv;
+    TCN_ALLOC_WSTRING(name);
+    tcn_nt_registry_t *k = J2P(key, tcn_nt_registry_t *);
+
+    UNREFERENCED(o);
+    rv = RegDeleteValueW(k->key, J2W(name));
+    TCN_FREE_WSTRING(name);
+    return (jint)rv;
+}
diff --git a/native/connector/os/win32/system.c b/native/connector/os/win32/system.c
new file mode 100644 (file)
index 0000000..5a85d43
--- /dev/null
@@ -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 <winsock2.h>
+#include <mswsock.h>
+#include <ws2tcpip.h>
+#include "apr.h"
+#include "apr_pools.h"
+#include "apr_poll.h"
+#include "apr_network_io.h"
+#include "apr_arch_misc.h" /* for apr_os_level */
+#include "apr_arch_atime.h"  /* for FileTimeToAprTime */
+
+#include "tcn.h"
+#include "ssl_private.h"
+
+#pragma warning(push)
+#pragma warning(disable : 4201)
+#if (_WIN32_WINNT < 0x0501)
+#include <winternl.h>
+#endif
+#include <psapi.h>
+#pragma warning(pop)
+
+
+static CRITICAL_SECTION dll_critical_section;   /* dll's critical section */
+static HINSTANCE        dll_instance = NULL;
+static SYSTEM_INFO      dll_system_info;
+static HANDLE           h_kernel = NULL;
+static HANDLE           h_ntdll  = NULL;
+static char             dll_file_name[MAX_PATH];
+
+typedef BOOL (WINAPI *pfnGetSystemTimes)(LPFILETIME, LPFILETIME, LPFILETIME);
+static pfnGetSystemTimes fnGetSystemTimes = NULL;
+#if (_WIN32_WINNT < 0x0501)
+typedef NTSTATUS (WINAPI *pfnNtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);
+static pfnNtQuerySystemInformation fnNtQuerySystemInformation = NULL;
+#endif
+
+BOOL
+WINAPI
+DllMain(
+    HINSTANCE instance,
+    DWORD reason,
+    LPVOID reserved)
+{
+
+    switch (reason) {
+        /** The DLL is loading due to process
+         *  initialization or a call to LoadLibrary.
+         */
+        case DLL_PROCESS_ATTACH:
+            InitializeCriticalSection(&dll_critical_section);
+            dll_instance = instance;
+            GetSystemInfo(&dll_system_info);
+            if ((h_kernel = LoadLibrary("kernel32.dll")) != NULL)
+                fnGetSystemTimes = (pfnGetSystemTimes)GetProcAddress(h_kernel,
+                                                            "GetSystemTimes");
+            if (fnGetSystemTimes == NULL) {
+                FreeLibrary(h_kernel);
+                h_kernel = NULL;
+#if (_WIN32_WINNT < 0x0501)
+                if ((h_ntdll = LoadLibrary("ntdll.dll")) != NULL)
+                    fnNtQuerySystemInformation =
+                        (pfnNtQuerySystemInformation)GetProcAddress(h_ntdll,
+                                                "NtQuerySystemInformation");
+
+                if (fnNtQuerySystemInformation == NULL) {
+                    FreeLibrary(h_ntdll);
+                    h_ntdll = NULL;
+                }
+#endif
+            }
+            GetModuleFileName(instance, dll_file_name, sizeof(dll_file_name));
+            break;
+        /** The attached process creates a new thread.
+         */
+        case DLL_THREAD_ATTACH:
+            break;
+
+        /** The thread of the attached process terminates.
+         */
+        case DLL_THREAD_DETACH:
+            break;
+
+        /** DLL unload due to process termination
+         *  or FreeLibrary.
+         */
+        case DLL_PROCESS_DETACH:
+            /* Make sure the library is always terminated */
+            apr_terminate();
+            if (h_kernel)
+                FreeLibrary(h_kernel);
+            if (h_ntdll)
+                FreeLibrary(h_ntdll);
+            DeleteCriticalSection(&dll_critical_section);
+            break;
+
+        default:
+            break;
+    }
+
+    return TRUE;
+    UNREFERENCED_PARAMETER(reserved);
+}
+
+
+TCN_IMPLEMENT_CALL(jstring, OS, syserror)(TCN_STDARGS, jint err)
+{
+    jstring str;
+    void *buf;
+
+    UNREFERENCED(o);
+    if (!FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
+                       FORMAT_MESSAGE_FROM_SYSTEM |
+                       FORMAT_MESSAGE_IGNORE_INSERTS,
+                       NULL,
+                       err,
+                       MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+                       (LPTSTR)&buf,
+                       0,
+                       NULL)) {
+        str = AJP_TO_JSTRING("Unknown Error");
+    }
+    else {
+        str = AJP_TO_JSTRING((const char *)buf);
+        LocalFree(buf);
+    }
+    return str;
+}
+
+TCN_IMPLEMENT_CALL(jstring, OS, expand)(TCN_STDARGS, jstring val)
+{
+    jstring str;
+    jchar buf[TCN_BUFFER_SZ] = L"";
+    DWORD len;
+    TCN_ALLOC_WSTRING(val);
+
+    UNREFERENCED(o);
+    TCN_INIT_WSTRING(val);
+
+    len = ExpandEnvironmentStringsW(J2W(val), buf, TCN_BUFFER_SZ - 1);
+    if (len > (TCN_BUFFER_SZ - 1)) {
+        jchar *dbuf = malloc((len + 1) * 2);
+        ExpandEnvironmentStringsW(J2W(val), dbuf, len);
+        str = (*e)->NewString(e, dbuf, wcslen(dbuf));
+        free(dbuf);
+    }
+    else
+        str = (*e)->NewString(e, buf, wcslen(buf));
+
+    TCN_FREE_WSTRING(val);
+    return str;
+}
+
+#define LOG_MSG_EMERG                    0xC0000001L
+#define LOG_MSG_ERROR                    0xC0000002L
+#define LOG_MSG_NOTICE                   0x80000003L
+#define LOG_MSG_WARN                     0x80000004L
+#define LOG_MSG_INFO                     0x40000005L
+#define LOG_MSG_DEBUG                    0x00000006L
+#define LOG_MSG_DOMAIN                   "Native"
+
+static char log_domain[MAX_PATH] = "Native";
+
+static void init_log_source(const char *domain)
+{
+    HKEY  key;
+    DWORD ts;
+    char event_key[MAX_PATH];
+
+    strcpy(event_key, "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\");
+    strcat(event_key, domain);
+    if (!RegCreateKey(HKEY_LOCAL_MACHINE, event_key, &key)) {
+        RegSetValueEx(key, "EventMessageFile", 0, REG_SZ, (LPBYTE)&dll_file_name[0],
+                      strlen(dll_file_name) + 1);
+        ts = EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE | EVENTLOG_INFORMATION_TYPE;
+
+        RegSetValueEx(key, "TypesSupported", 0, REG_DWORD, (LPBYTE) &ts, sizeof(DWORD));
+        RegCloseKey(key);
+    }
+    strcpy(log_domain, domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, sysloginit)(TCN_STDARGS, jstring domain)
+{
+    const char *d;
+    TCN_ALLOC_CSTRING(domain);
+
+    UNREFERENCED(o);
+
+    if ((d = J2S(domain)) == NULL)
+        d = LOG_MSG_DOMAIN;
+    init_log_source(d);
+
+    TCN_FREE_CSTRING(domain);
+}
+
+TCN_IMPLEMENT_CALL(void, OS, syslog)(TCN_STDARGS, jint level,
+                                     jstring msg)
+{
+    TCN_ALLOC_CSTRING(msg);
+    DWORD id = LOG_MSG_DEBUG;
+    WORD  il = EVENTLOG_SUCCESS;
+    HANDLE  source;
+    const char *messages[1];
+    UNREFERENCED(o);
+
+    switch (level) {
+        case TCN_LOG_EMERG:
+            id = LOG_MSG_EMERG;
+            il = EVENTLOG_ERROR_TYPE;
+        break;
+        case TCN_LOG_ERROR:
+            id = LOG_MSG_ERROR;
+            il = EVENTLOG_ERROR_TYPE;
+        break;
+        case TCN_LOG_NOTICE:
+            id = LOG_MSG_NOTICE;
+            il = EVENTLOG_WARNING_TYPE;
+        break;
+        case TCN_LOG_WARN:
+            id = LOG_MSG_WARN;
+            il = EVENTLOG_WARNING_TYPE;
+        break;
+        case TCN_LOG_INFO:
+            id = LOG_MSG_INFO;
+            il = EVENTLOG_INFORMATION_TYPE;
+        break;
+    }
+
+    messages[0] = J2S(msg);
+    source = RegisterEventSource(NULL, log_domain);
+
+    if (source != NULL) {
+        ReportEvent(source, il,
+                    0,
+                    id,
+                    NULL,
+                    1, 0,
+                    messages, NULL);
+        DeregisterEventSource(source);
+    }
+
+    TCN_FREE_CSTRING(msg);
+}
+
+TCN_IMPLEMENT_CALL(jboolean, OS, is)(TCN_STDARGS, jint type)
+{
+    UNREFERENCED_STDARGS;
+#ifdef _WIN64
+    if (type == 4)
+        return JNI_TRUE;
+    else
+#endif
+    if (type == 3)
+        return JNI_TRUE;
+    else
+        return JNI_FALSE;
+}
+
+TCN_IMPLEMENT_CALL(jint, OS, info)(TCN_STDARGS,
+                                   jlongArray inf)
+{
+    MEMORYSTATUSEX ms;
+    ULONGLONG st[4];
+    FILETIME ft[4];
+    PROCESS_MEMORY_COUNTERS pmc;
+    jint rv;
+    int i;
+    jsize ilen = (*e)->GetArrayLength(e, inf);
+    jlong *pvals = (*e)->GetLongArrayElements(e, inf, NULL);
+
+    if (ilen < 16) {
+        return APR_EINVAL;
+    }
+    for (i = 0; i < 16; i++)
+        pvals[i] = 0;
+
+    ms.dwLength = sizeof(MEMORYSTATUSEX);
+
+    UNREFERENCED(o);
+    if (GlobalMemoryStatusEx(&ms)) {
+        pvals[0] = (jlong)ms.ullTotalPhys;
+        pvals[1] = (jlong)ms.ullAvailPhys;
+        pvals[2] = (jlong)ms.ullTotalPageFile;
+        pvals[3] = (jlong)ms.ullAvailPageFile;
+        /* Slots 4 and 5 are for shared memory */
+        pvals[6] = (jlong)ms.dwMemoryLoad;
+    }
+    else
+        goto cleanup;
+
+    memset(st, 0, sizeof(st));
+
+    if (fnGetSystemTimes) {
+        if ((*fnGetSystemTimes)(&ft[0], &ft[1], &ft[2])) {
+            st[0] = (((ULONGLONG)ft[0].dwHighDateTime << 32) | ft[0].dwLowDateTime) / 10;
+            st[1] = (((ULONGLONG)ft[1].dwHighDateTime << 32) | ft[1].dwLowDateTime) / 10;
+            st[2] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
+        }
+        else
+            goto cleanup;
+    }
+#if (_WIN32_WINNT < 0x0501)
+    else if (fnNtQuerySystemInformation) {
+        BYTE buf[2048]; /* This should ne enough for 32 processors */
+        NTSTATUS rs = (*fnNtQuerySystemInformation)(SystemProcessorPerformanceInformation,
+                                           (LPVOID)buf, 2048, NULL);
+        if (rs == 0) {
+            PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION pspi = (PSYSTEM_PROCESSOR_PERFORMANCE_INFORMATION)&buf[0];
+            DWORD i;
+            /* Calculate all processors */
+            for (i = 0; i < dll_system_info.dwNumberOfProcessors; i++) {
+                st[0] += pspi[i].IdleTime.QuadPart / 10;
+                st[1] += pspi[i].KernelTime.QuadPart / 10;
+                st[2] += pspi[i].UserTime.QuadPart / 10;
+            }
+        }
+        else
+            goto cleanup;
+    }
+#endif
+    pvals[7] = st[0];
+    pvals[8] = st[1];
+    pvals[9] = st[2];
+
+    memset(st, 0, sizeof(st));
+    if (GetProcessTimes(GetCurrentProcess(), &ft[0], &ft[1], &ft[2], &ft[3])) {
+        FileTimeToAprTime((apr_time_t *)&st[0], &ft[0]);
+        st[1] = (((ULONGLONG)ft[2].dwHighDateTime << 32) | ft[2].dwLowDateTime) / 10;
+        st[2] = (((ULONGLONG)ft[3].dwHighDateTime << 32) | ft[3].dwLowDateTime) / 10;
+    }
+    pvals[10] = st[0];
+    pvals[11] = st[1];
+    pvals[12] = st[2];
+
+    if (GetProcessMemoryInfo(GetCurrentProcess(), &pmc, sizeof(pmc))) {
+        pvals[13] = pmc.WorkingSetSize;
+        pvals[14] = pmc.PeakWorkingSetSize;
+        pvals[15] = pmc.PageFaultCount;
+    }
+
+    (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+    return APR_SUCCESS;
+cleanup:
+    rv = apr_get_os_error();
+    (*e)->ReleaseLongArrayElements(e, inf, pvals, 0);
+    return rv;
+}
+
+static DWORD WINAPI password_thread(void *data)
+{
+    tcn_pass_cb_t *cb = (tcn_pass_cb_t *)data;
+    MSG     msg;
+    HWINSTA hwss;
+    HWINSTA hwsu;
+    HDESK   hwds;
+    HDESK   hwdu;
+    HWND    hwnd;
+
+    /* Ensure connection to service window station and desktop, and
+     * save their handles.
+     */
+    GetDesktopWindow();
+    hwss = GetProcessWindowStation();
+    hwds = GetThreadDesktop(GetCurrentThreadId());
+
+    /* Impersonate the client and connect to the User's
+     * window station and desktop.
+     */
+    hwsu = OpenWindowStation("WinSta0", FALSE, MAXIMUM_ALLOWED);
+    if (hwsu == NULL) {
+        ExitThread(1);
+        return 1;
+    }
+    SetProcessWindowStation(hwsu);
+    hwdu = OpenDesktop("Default", 0, FALSE, MAXIMUM_ALLOWED);
+    if (hwdu == NULL) {
+        SetProcessWindowStation(hwss);
+        CloseWindowStation(hwsu);
+        ExitThread(1);
+        return 1;
+    }
+    SetThreadDesktop(hwdu);
+
+    hwnd = CreateDialog(dll_instance, MAKEINTRESOURCE(1001), NULL, NULL);
+    if (hwnd != NULL)
+        ShowWindow(hwnd, SW_SHOW);
+    else  {
+        ExitThread(1);
+        return 1;
+    }
+    while (1) {
+        if (PeekMessage(&msg, hwnd, 0, 0, PM_REMOVE)) {
+            if (msg.message == WM_KEYUP) {
+                int nVirtKey = (int)msg.wParam;
+                if (nVirtKey == VK_ESCAPE) {
+                    DestroyWindow(hwnd);
+                    break;
+                }
+                else if (nVirtKey == VK_RETURN) {
+                    HWND he = GetDlgItem(hwnd, 1002);
+                    if (he) {
+                        int n = GetWindowText(he, cb->password, SSL_MAX_PASSWORD_LEN - 1);
+                        cb->password[n] = '\0';
+                    }
+                    DestroyWindow(hwnd);
+                    break;
+                }
+            }
+            TranslateMessage(&msg);
+            DispatchMessage(&msg);
+        }
+        else
+            Sleep(100);
+    }
+    /* Restore window station and desktop.
+     */
+    SetThreadDesktop(hwds);
+    SetProcessWindowStation(hwss);
+    CloseDesktop(hwdu);
+    CloseWindowStation(hwsu);
+
+    ExitThread(0);
+    return 0;
+}
+
+int WIN32_SSL_password_prompt(tcn_pass_cb_t *data)
+{
+    DWORD id;
+    HANDLE thread;
+    /* TODO: See how to display this from service mode */
+    thread = CreateThread(NULL, 0,
+                password_thread, data,
+                0, &id);
+    WaitForSingleObject(thread, INFINITE);
+    CloseHandle(thread);
+    return (int)strlen(data->password);
+}
+
+
diff --git a/native/connector/src/address.c b/native/connector/src/address.c
new file mode 100644 (file)
index 0000000..41e4797
--- /dev/null
@@ -0,0 +1,105 @@
+/* Copyright 2000-2006 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/*\r
+ *\r
+ * @author Mladen Turk\r
+ * @version $Revision: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $\r
+ */\r
+\r
+#include "tcn.h"\r
+\r
+TCN_IMPLEMENT_CALL(jlong, Address, info)(TCN_STDARGS,\r
+                                         jstring hostname,\r
+                                         jint family, jint port,\r
+                                         jint flags, jlong pool)\r
+{\r
+    apr_pool_t *p = J2P(pool, apr_pool_t *);\r
+    TCN_ALLOC_CSTRING(hostname);\r
+    apr_sockaddr_t *sa = NULL;\r
+    apr_int32_t f;\r
+\r
+\r
+    UNREFERENCED(o);\r
+    GET_S_FAMILY(f, family);\r
+    TCN_THROW_IF_ERR(apr_sockaddr_info_get(&sa,\r
+            J2S(hostname), f, (apr_port_t)port,\r
+            (apr_int32_t)flags, p), sa);\r
+\r
+cleanup:\r
+    TCN_FREE_CSTRING(hostname);\r
+    return P2J(sa);\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jstring, Address, getnameinfo)(TCN_STDARGS,\r
+                                                  jlong sa, jint flags)\r
+{\r
+    apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);\r
+    char *hostname;\r
+\r
+    UNREFERENCED(o);\r
+    if (apr_getnameinfo(&hostname, s, (apr_int32_t)flags) == APR_SUCCESS)\r
+        return AJP_TO_JSTRING(hostname);\r
+    else\r
+        return NULL;\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jstring, Address, getip)(TCN_STDARGS, jlong sa)\r
+{\r
+    apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);\r
+    char *ipaddr;\r
+\r
+    UNREFERENCED(o);\r
+    if (apr_sockaddr_ip_get(&ipaddr, s) == APR_SUCCESS)\r
+        return AJP_TO_JSTRING(ipaddr);\r
+    else\r
+        return NULL;\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jlong, Address, get)(TCN_STDARGS, jint which,\r
+                                        jlong sock)\r
+{\r
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+    apr_sockaddr_t *sa = NULL;\r
+\r
+    UNREFERENCED(o);\r
+    TCN_THROW_IF_ERR(apr_socket_addr_get(&sa,\r
+                        (apr_interface_e)which, s->sock), sa);\r
+cleanup:\r
+    return P2J(sa);\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jint, Address, equal)(TCN_STDARGS,\r
+                                         jlong a, jlong b)\r
+{\r
+    apr_sockaddr_t *sa = J2P(a, apr_sockaddr_t *);\r
+    apr_sockaddr_t *sb = J2P(b, apr_sockaddr_t *);\r
+\r
+    UNREFERENCED_STDARGS;\r
+    return apr_sockaddr_equal(sa, sb) ? JNI_TRUE : JNI_FALSE;\r
+}\r
+\r
+TCN_IMPLEMENT_CALL(jint, Address, getservbyname)(TCN_STDARGS,\r
+                                                 jlong sa, jstring servname)\r
+{\r
+    apr_sockaddr_t *s = J2P(sa, apr_sockaddr_t *);\r
+    TCN_ALLOC_CSTRING(servname);\r
+    apr_status_t rv;\r
+\r
+    UNREFERENCED(o);\r
+    rv = apr_getservbyname(s, J2S(servname));\r
+    TCN_FREE_CSTRING(servname);\r
+    return (jint)rv;\r
+}\r
diff --git a/native/connector/src/dir.c b/native/connector/src/dir.c
new file mode 100644 (file)
index 0000000..4900039
--- /dev/null
@@ -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 (file)
index 0000000..20bdc59
--- /dev/null
@@ -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,
+                                      "<init>",
+                                      "(ILjava/lang/String;)V");
+    if (constructorID == NULL) {
+        fprintf(stderr,
+                "Cannot find constructor for " TCN_ERROR_CLASS " class\n");
+        goto cleanup;
+    }
+
+    apr_strerror(err, serr, 512);
+    /* Obtain the string objects */
+    jdescription = AJP_TO_JSTRING(serr);
+    if (jdescription == NULL) {
+        fprintf(stderr,
+                "Cannot allocate description for " TCN_ERROR_CLASS " class\n");
+        goto cleanup;
+    }
+    /* Create the APR Error object */
+    throwObj = (*e)->NewObject(e, aprErrorClass, constructorID,
+                               (jint)err, jdescription);
+    if (throwObj == NULL) {
+        fprintf(stderr,
+                "Cannot allocate new " TCN_ERROR_CLASS " object\n");
+        goto cleanup;
+    }
+
+    (*e)->Throw(e, throwObj);
+cleanup:
+    (*e)->DeleteLocalRef(e, aprErrorClass);
+}
+
+
+TCN_IMPLEMENT_CALL(jint, Error, osError)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jint)apr_get_os_error();
+}
+
+TCN_IMPLEMENT_CALL(jint, Error, netosError)(TCN_STDARGS)
+{
+    UNREFERENCED_STDARGS;
+    return (jint)apr_get_netos_error();
+}
+
+TCN_IMPLEMENT_CALL(jstring, Error, strerror)(TCN_STDARGS, jint err)
+{
+    char serr[512] = {0};
+    jstring jerr;
+
+    UNREFERENCED(o);
+    if (err >= TCN_TIMEUP && err <= TCN_ETIMEDOUT) {
+        err -= TCN_TIMEUP;
+        jerr = AJP_TO_JSTRING(tcn_errors[err + 1]);
+    }
+    else {
+        apr_strerror(err, serr, 512);
+        jerr = AJP_TO_JSTRING(serr);
+    }
+    return jerr;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Status, is)(TCN_STDARGS, jint err, jint idx)
+{
+#define APR_IS(I, E) case I: if (E(err)) return JNI_TRUE; break
+#define APR_ISX(I, E, T) case I: if (E(err) || (err == T)) return JNI_TRUE; break
+
+    UNREFERENCED_STDARGS;
+    switch (idx) {
+        APR_IS(1,  APR_STATUS_IS_ENOSTAT);
+        APR_IS(2,  APR_STATUS_IS_ENOPOOL);
+        /* empty slot: +3 */
+        APR_IS(4,  APR_STATUS_IS_EBADDATE);
+        APR_IS(5,  APR_STATUS_IS_EINVALSOCK);
+        APR_IS(6,  APR_STATUS_IS_ENOPROC);
+        APR_IS(7,  APR_STATUS_IS_ENOTIME);
+        APR_IS(8,  APR_STATUS_IS_ENODIR);
+        APR_IS(9,  APR_STATUS_IS_ENOLOCK);
+        APR_IS(10, APR_STATUS_IS_ENOPOLL);
+        APR_IS(11, APR_STATUS_IS_ENOSOCKET);
+        APR_IS(12, APR_STATUS_IS_ENOTHREAD);
+        APR_IS(13, APR_STATUS_IS_ENOTHDKEY);
+        APR_IS(14, APR_STATUS_IS_EGENERAL);
+        APR_IS(15, APR_STATUS_IS_ENOSHMAVAIL);
+        APR_IS(16, APR_STATUS_IS_EBADIP);
+        APR_IS(17, APR_STATUS_IS_EBADMASK);
+        /* empty slot: +18 */
+        APR_IS(19, APR_STATUS_IS_EDSOOPEN);
+        APR_IS(20, APR_STATUS_IS_EABSOLUTE);
+        APR_IS(21, APR_STATUS_IS_ERELATIVE);
+        APR_IS(22, APR_STATUS_IS_EINCOMPLETE);
+        APR_IS(23, APR_STATUS_IS_EABOVEROOT);
+        APR_IS(24, APR_STATUS_IS_EBADPATH);
+        APR_IS(25, APR_STATUS_IS_EPATHWILD);
+        APR_IS(26, APR_STATUS_IS_ESYMNOTFOUND);
+        APR_IS(27, APR_STATUS_IS_EPROC_UNKNOWN);
+        APR_IS(28, APR_STATUS_IS_ENOTENOUGHENTROPY);
+
+
+        /* APR_Error */
+        APR_IS(51, APR_STATUS_IS_INCHILD);
+        APR_IS(52, APR_STATUS_IS_INPARENT);
+        APR_IS(53, APR_STATUS_IS_DETACH);
+        APR_IS(54, APR_STATUS_IS_NOTDETACH);
+        APR_IS(55, APR_STATUS_IS_CHILD_DONE);
+        APR_IS(56, APR_STATUS_IS_CHILD_NOTDONE);
+        APR_ISX(57, APR_STATUS_IS_TIMEUP, TCN_TIMEUP);
+        APR_IS(58, APR_STATUS_IS_INCOMPLETE);
+        /* empty slot: +9 */
+        /* empty slot: +10 */
+        /* empty slot: +11 */
+        APR_IS(62, APR_STATUS_IS_BADCH);
+        APR_IS(63, APR_STATUS_IS_BADARG);
+        APR_IS(64, APR_STATUS_IS_EOF);
+        APR_IS(65, APR_STATUS_IS_NOTFOUND);
+        /* empty slot: +16 */
+        /* empty slot: +17 */
+        /* empty slot: +18 */
+        APR_IS(69, APR_STATUS_IS_ANONYMOUS);
+        APR_IS(70, APR_STATUS_IS_FILEBASED);
+        APR_IS(71, APR_STATUS_IS_KEYBASED);
+        APR_IS(72, APR_STATUS_IS_EINIT);
+        APR_IS(73, APR_STATUS_IS_ENOTIMPL);
+        APR_IS(74, APR_STATUS_IS_EMISMATCH);
+        APR_IS(75, APR_STATUS_IS_EBUSY);
+        /* Socket errors */
+        APR_ISX(90, APR_STATUS_IS_EAGAIN, TCN_EAGAIN);
+        APR_ISX(91, TCN_STATUS_IS_ETIMEDOUT, TCN_ETIMEDOUT);
+        APR_IS(92, APR_STATUS_IS_ECONNABORTED);
+        APR_IS(93, APR_STATUS_IS_ECONNRESET);
+        APR_ISX(94, APR_STATUS_IS_EINPROGRESS, TCN_EINPROGRESS);
+        APR_ISX(95, APR_STATUS_IS_EINTR, TCN_EINTR);
+        APR_IS(96, APR_STATUS_IS_ENOTSOCK);
+        APR_IS(97, APR_STATUS_IS_EINVAL);
+    }
+    return JNI_FALSE;
+}
diff --git a/native/connector/src/file.c b/native/connector/src/file.c
new file mode 100644 (file)
index 0000000..ff669b4
--- /dev/null
@@ -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 (file)
index 0000000..76716c5
--- /dev/null
@@ -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,
+                                      "<init>", "()V");
+    if (finfo_class_init == NULL)
+        goto cleanup;
+    finfo_class_initialized = 1;
+    finfo_class = finfo;
+cleanup:
+    return APR_SUCCESS;
+}
+
+apr_status_t tcn_load_ainfo_class(JNIEnv *e, jclass ainfo)
+{
+    GET_AINFO_J(pool);
+    GET_AINFO_S(hostname);
+    GET_AINFO_S(servname);
+    GET_AINFO_I(port);
+    GET_AINFO_I(family);
+    GET_AINFO_J(next);
+    ainfo_class_init = (*e)->GetMethodID(e, ainfo,
+                                      "<init>", "()V");
+
+    if (ainfo_class_init == NULL)
+        goto cleanup;
+    ainfo_class_initialized = 1;
+    ainfo_class = ainfo;
+cleanup:
+    return APR_SUCCESS;
+}
+
+static void fill_finfo(JNIEnv *e, jobject obj, apr_finfo_t *info)
+{
+
+    SET_FINFO_J(pool, P2J(info->pool));
+    SET_FINFO_I(valid, info->valid);
+    SET_FINFO_I(protection, info->protection);
+    SET_FINFO_I(filetype, info->filetype);
+    SET_FINFO_I(user, ((jlong)info->user));
+    SET_FINFO_I(group, ((jlong)info->group));
+    SET_FINFO_I(inode, info->inode);
+    SET_FINFO_I(device, info->device);
+    SET_FINFO_I(nlink, info->nlink);
+    SET_FINFO_J(size, info->size);
+    SET_FINFO_J(csize, info->csize);
+    SET_FINFO_J(atime, info->atime);
+    SET_FINFO_J(mtime, info->mtime);
+    SET_FINFO_J(ctime, info->ctime);
+    SET_FINFO_S(fname, info->fname);
+    SET_FINFO_S(name, info->name);
+    SET_FINFO_J(filehand, P2J(info->filehand));
+}
+
+static void fill_ainfo(JNIEnv *e, jobject obj, apr_sockaddr_t *info)
+{
+
+    SET_AINFO_J(pool, P2J(info->pool));
+    SET_AINFO_S(hostname, info->hostname);
+    SET_AINFO_S(servname, info->servname);
+    SET_AINFO_I(port, info->port);
+    SET_AINFO_I(family, info->family);
+    SET_AINFO_J(next, P2J(info->next));
+
+}
+
+TCN_IMPLEMENT_CALL(jint, File, stat)(TCN_STDARGS, jobject finfo,
+                                     jstring fname, jint wanted,
+                                     jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(fname);
+    apr_status_t rv;
+    apr_finfo_t info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_stat(&info, J2S(fname), wanted, p)) == APR_SUCCESS) {
+        jobject io = (*e)->NewLocalRef(e, finfo);
+        fill_finfo(e, io, &info);
+        (*e)->DeleteLocalRef(e, io);
+    }
+    TCN_FREE_CSTRING(fname);
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, File, getStat)(TCN_STDARGS, jstring fname,
+                                           jint wanted, jlong pool)
+{
+    apr_pool_t *p = J2P(pool, apr_pool_t *);
+    TCN_ALLOC_CSTRING(fname);
+    apr_status_t rv;
+    apr_finfo_t info;
+    jobject finfo = NULL;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_stat(&info, J2S(fname), wanted, p)) == APR_SUCCESS) {
+        finfo = (*e)->NewObject(e, finfo_class, finfo_class_init);
+        if (finfo == NULL)
+            goto cleanup;
+        fill_finfo(e, finfo, &info);
+    }
+    else
+        tcn_ThrowAPRException(e, rv);
+cleanup:
+    TCN_FREE_CSTRING(fname);
+    return finfo;
+}
+
+TCN_IMPLEMENT_CALL(jint, File, infoGet)(TCN_STDARGS, jobject finfo,
+                                        jint wanted, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_status_t rv;
+    apr_finfo_t info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_file_info_get(&info, wanted, f)) == APR_SUCCESS) {
+        jobject io = (*e)->NewLocalRef(e, finfo);
+        fill_finfo(e, io, &info);
+        (*e)->DeleteLocalRef(e, io);
+    }
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, File, getInfo)(TCN_STDARGS, jint wanted, jlong file)
+{
+    apr_file_t *f = J2P(file, apr_file_t *);
+    apr_status_t rv;
+    apr_finfo_t  info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_file_info_get(&info, wanted, f)) == APR_SUCCESS) {
+        jobject finfo;
+        finfo = (*e)->NewObject(e, finfo_class, finfo_class_init);
+        if (finfo == NULL)
+            return NULL;
+        fill_finfo(e, finfo, &info);
+        return finfo;
+    }
+    else
+        tcn_ThrowAPRException(e, rv);
+    return NULL;
+}
+
+TCN_IMPLEMENT_CALL(jint, Directory, read)(TCN_STDARGS, jobject finfo,
+                                          jint wanted, jlong dir)
+{
+    apr_dir_t *d = J2P(dir, apr_dir_t *);
+    apr_status_t rv;
+    apr_finfo_t info;
+
+    UNREFERENCED(o);
+
+    if ((rv =  apr_dir_read(&info, wanted, d)) == APR_SUCCESS) {
+        jobject io = (*e)->NewLocalRef(e, finfo);
+        fill_finfo(e, io, &info);
+        if ((*e)->ExceptionCheck(e)) {
+            (*e)->ExceptionClear(e);
+        }
+        else
+            rv = APR_EGENERAL;
+        (*e)->DeleteLocalRef(e, io);
+    }
+    return (jint)rv;
+}
+
+TCN_IMPLEMENT_CALL(jboolean, Address, fill)(TCN_STDARGS,
+                                            jobject addr, jlong info)
+{
+    apr_sockaddr_t *i = J2P(info, apr_sockaddr_t *);
+    jobject ao;
+    jboolean rv = JNI_FALSE;
+
+    UNREFERENCED(o);
+
+    if (i) {
+        ao = (*e)->NewLocalRef(e, addr);
+        fill_ainfo(e, ao, i);
+        if ((*e)->ExceptionCheck(e)) {
+            (*e)->ExceptionClear(e);
+        }
+        else
+            rv = JNI_TRUE;
+        (*e)->DeleteLocalRef(e, ao);
+    }
+    return rv;
+}
+
+TCN_IMPLEMENT_CALL(jobject, Address, getInfo)(TCN_STDARGS, jlong info)
+{
+    apr_sockaddr_t *i = J2P(info, apr_sockaddr_t *);
+    jobject sockaddrObj = NULL;
+
+    UNREFERENCED(o);
+
+    /* Create the APR Error object */
+    sockaddrObj = (*e)->NewObject(e, ainfo_class, ainfo_class_init);
+    if (sockaddrObj == NULL)
+        return NULL;
+    fill_ainfo(e, sockaddrObj, i);
+    return sockaddrObj;
+}
diff --git a/native/connector/src/jnilib.c b/native/connector/src/jnilib.c
new file mode 100644 (file)
index 0000000..c48647b
--- /dev/null
@@ -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,
+                   "<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 (file)
index 0000000..b93cd61
--- /dev/null
@@ -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 (file)
index 0000000..d9c7c2a
--- /dev/null
@@ -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 (file)
index 0000000..c4e96e4
--- /dev/null
@@ -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 (file)
index 0000000..1306c9c
--- /dev/null
@@ -0,0 +1,71 @@
+/* Copyright 2000-2006 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/*\r
+ *\r
+ * @author Mladen Turk\r
+ * @version $Revision: 416783 $, $Date: 2006-06-23 20:06:15 +0200 (pet, 23 lip 2006) $\r
+ */\r
+\r
+#include "tcn.h"\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, join)(TCN_STDARGS,\r
+                                         jlong sock, jlong join,\r
+                                         jlong iface, jlong source)\r
+{\r
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+    apr_sockaddr_t *ja = J2P(join, apr_sockaddr_t *);\r
+    apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);\r
+    apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *);\r
+    UNREFERENCED_STDARGS;\r
+    return (jint)apr_mcast_join(s->sock, ja, ia, sa);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, leave)(TCN_STDARGS,\r
+                                          jlong sock, jlong addr,\r
+                                          jlong iface, jlong source)\r
+{\r
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+    apr_sockaddr_t *aa = J2P(addr, apr_sockaddr_t *);\r
+    apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);\r
+    apr_sockaddr_t *sa = J2P(source, apr_sockaddr_t *);\r
+    UNREFERENCED_STDARGS;\r
+    return (jint)apr_mcast_leave(s->sock, aa, ia, sa);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, hops)(TCN_STDARGS,\r
+                                         jlong sock, jint ttl)\r
+{\r
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+    UNREFERENCED_STDARGS;\r
+    return (jint)apr_mcast_hops(s->sock, (apr_byte_t)ttl);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, loopback)(TCN_STDARGS,\r
+                                             jlong sock, jboolean opt)\r
+{\r
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+    UNREFERENCED_STDARGS;\r
+    return (jint)apr_mcast_loopback(s->sock, opt == JNI_TRUE ? 1 : 0);\r
+};\r
+\r
+TCN_IMPLEMENT_CALL(jint, Mulicast, ointerface)(TCN_STDARGS,\r
+                                               jlong sock, jlong iface)\r
+{\r
+    tcn_socket_t *s = J2P(sock, tcn_socket_t *);\r
+    apr_sockaddr_t *ia = J2P(iface, apr_sockaddr_t *);\r
+    UNREFERENCED_STDARGS;\r
+    return (jint)apr_mcast_interface(s->sock, ia);\r
+};\r
diff --git a/native/connector/src/network.c b/native/connector/src/network.c
new file mode 100644 (file)
index 0000000..89c6236
--- /dev/null
@@ -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 (file)
index 0000000..703e740
--- /dev/null
@@ -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 (file)
index 0000000..7f47ae3
--- /dev/null
@@ -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 (file)
index 0000000..51c9159
--- /dev/null
@@ -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 (file)
index 0000000..965f41d
--- /dev/null
@@ -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 (file)
index 0000000..82eb613
--- /dev/null
@@ -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 (file)
index 0000000..67a4bbf
--- /dev/null
@@ -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 (file)
index 0000000..38a4772
--- /dev/null
@@ -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 (file)
index 0000000..bf8dd23
--- /dev/null
@@ -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 (file)
index 0000000..c792372
--- /dev/null
@@ -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 (file)
index 0000000..c875953
--- /dev/null
@@ -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 (file)
index 0000000..59ac460
--- /dev/null
@@ -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 (file)
index 0000000..53e1113
--- /dev/null
@@ -0,0 +1,28 @@
+/* Copyright 2000-2005 The Apache Software Foundation\r
+ *\r
+ * Licensed under the Apache License, Version 2.0 (the "License");\r
+ * you may not use this file except in compliance with the License.\r
+ * You may obtain a copy of the License at\r
+ *\r
+ *     http://www.apache.org/licenses/LICENSE-2.0\r
+ *\r
+ * Unless required by applicable law or agreed to in writing, software\r
+ * distributed under the License is distributed on an "AS IS" BASIS,\r
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
+ * See the License for the specific language governing permissions and\r
+ * limitations under the License.\r
+ */\r
+\r
+/*\r
+ *\r
+ * @author Mladen Turk\r
+ * @version $Revision: 393735 $, $Date: 2006-04-13 08:41:49 +0200 (čet, 13 tra 2006) $\r
+ */\r
+\r
+#include "tcn.h"\r
+\r
+TCN_IMPLEMENT_CALL(jlong, Thread, current)(TCN_STDARGS)\r
+{\r
+    UNREFERENCED_STDARGS;\r
+    return (jlong)((unsigned long)apr_os_thread_current());\r
+}\r
diff --git a/native/connector/src/user.c b/native/connector/src/user.c
new file mode 100644 (file)
index 0000000..33713fd
--- /dev/null
@@ -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 (file)
index 0000000..5e5c46d
--- /dev/null
@@ -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 (file)
index 0000000..f6ae98a
--- /dev/null
@@ -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}