You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@harmony.apache.org by od...@apache.org on 2010/09/10 18:01:18 UTC

svn commit: r995839 - in /harmony/enhanced/java/branches/omd/classlib/modules/x-net/src: main/java/javax/net/ssl/ main/java/org/apache/harmony/xnet/provider/jsse/ main/native/jsse/shared/ main/native/jsse/unix/ test/api/java/org/apache/harmony/xnet/tes...

Author: odeakin
Date: Fri Sep 10 16:01:18 2010
New Revision: 995839

URL: http://svn.apache.org/viewvc?rev=995839&view=rev
Log:
Apply x-net-4.patch for HARMONY-6627 ([classlib][x-net] Creating a JSSE provider based on OpenSSL) with some very minor modifications (details in the JIRA).

Modified:
    harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/javax/net/ssl/SSLEngineResult.java
    harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
    harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLEngineImpl.java
    harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.c
    harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.h
    harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/unix/exports.txt
    harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/test/api/java/org/apache/harmony/xnet/tests/javax/net/ssl/SSLEngineTest.java

Modified: harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/javax/net/ssl/SSLEngineResult.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/javax/net/ssl/SSLEngineResult.java?rev=995839&r1=995838&r2=995839&view=diff
==============================================================================
--- harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/javax/net/ssl/SSLEngineResult.java (original)
+++ harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/javax/net/ssl/SSLEngineResult.java Fri Sep 10 16:01:18 2010
@@ -26,7 +26,7 @@ public class SSLEngineResult {
     /**
      * The {@code enum} describing the state of the current handshake.
      */
-    public enum HandshakeStatus {
+    public static enum HandshakeStatus {
         /**
          * No handshake in progress.
          */

Modified: harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java?rev=995839&r1=995838&r2=995839&view=diff
==============================================================================
--- harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java (original)
+++ harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/JSSEProvider.java Fri Sep 10 16:01:18 2010
@@ -108,6 +108,9 @@ public final class JSSEProvider extends 
             public Void run() {
                 put("SSLContext.TLS", SSLContextImpl.class.getName());
                 put("Alg.Alias.SSLContext.TLSv1", "TLS");
+                put("SSLContext.SSL", SSLContextImpl.class.getName());
+                put("Alg.Alias.SSLContext.SSLv3", "SSL");
+                put("Alg.Alias.SSLContext.SSLv2", "SSL");
                 put("KeyManagerFactory.X509", KeyManagerFactoryImpl.class.getName());
                 put("TrustManagerFactory.X509", TrustManagerFactoryImpl.class.getName());
                 return null;

Modified: harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLEngineImpl.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLEngineImpl.java?rev=995839&r1=995838&r2=995839&view=diff
==============================================================================
--- harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLEngineImpl.java (original)
+++ harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/java/org/apache/harmony/xnet/provider/jsse/SSLEngineImpl.java Fri Sep 10 16:01:18 2010
@@ -21,10 +21,15 @@ import org.apache.harmony.xnet.provider.
 import org.apache.harmony.xnet.provider.jsse.SSLSessionImpl;
 import org.apache.harmony.xnet.provider.jsse.SSLEngineDataStream;
 
+import java.io.FileDescriptor;
 import java.io.IOException;
+import java.lang.reflect.Field;
 import java.nio.BufferUnderflowException;
 import java.nio.ByteBuffer;
 import java.nio.ReadOnlyBufferException;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLHandshakeException;
 import javax.net.ssl.SSLEngineResult;
@@ -85,9 +90,11 @@ public class SSLEngineImpl extends SSLEn
 
     // Pointer to the OpenSSL SSL struct used for this engine
     private long SSL;
-
+    
+    private SSLEngineResult.HandshakeStatus handshakeStatus;
+    
     private native long initImpl(long context);
-
+    
     /**
      * Ctor
      * @param   sslParameters:  SSLParameters
@@ -110,6 +117,11 @@ public class SSLEngineImpl extends SSLEn
         SSL = initImpl(sslParameters.getSSLContextAddress());
     }
 
+    private native SSLEngineResult.HandshakeStatus connectImpl(long sslContextAddress);
+    private native SSLEngineResult.HandshakeStatus acceptImpl(long sslContextAddress);
+    private native SSLEngineResult wrapImpl(long sslContextAddress,
+            byte[] src, int src_len, byte[] dst, int dst_len);
+    
     /**
      * Starts the handshake.
      * @throws  SSLException
@@ -124,20 +136,29 @@ public class SSLEngineImpl extends SSLEn
         if (!peer_mode_was_set) {
             throw new IllegalStateException("Client/Server mode was not set");
         }
+        // TODO: need to repeat connect/accept if status was waiting on wrap/unwrap previously?
         if (!handshake_started) {
             handshake_started = true;
-            if (getUseClientMode()) {
-                //handshakeProtocol = new ClientHandshakeImpl(this);
+
+            if (sslParameters.getUseClientMode()) {
+                if (logger != null) {
+                    logger.println("SSLEngineImpl: CLIENT connecting");
+                }
+
+                handshakeStatus = connectImpl(SSL);
             } else {
-                //handshakeProtocol = new ServerHandshakeImpl(this);
+                if (logger != null) {
+                    logger.println("SSLEngineImpl: SERVER accepting connection");
+                }
+                handshakeStatus = acceptImpl(SSL);
             }
-            appData = new SSLEngineAppData();
-            alertProtocol = new AlertProtocol();
-            recProtIS = new SSLBufferedInput();
-            recordProtocol = new SSLRecordProtocol(handshakeProtocol,
-                    alertProtocol, recProtIS, appData);
+//            appData = new SSLEngineAppData();
+//            alertProtocol = new AlertProtocol();
+//            recProtIS = new SSLBufferedInput();
+//            recordProtocol = new SSLRecordProtocol(handshakeProtocol,
+//                    alertProtocol, recProtIS, appData);
         }
-        handshakeProtocol.start();
+//        handshakeProtocol.start();
     }
 
     /**
@@ -206,7 +227,8 @@ public class SSLEngineImpl extends SSLEn
      */
     @Override
     public Runnable getDelegatedTask() {
-        return handshakeProtocol.getTask();
+        return null;
+        //return handshakeProtocol.getTask();
     }
 
     /**
@@ -370,17 +392,18 @@ public class SSLEngineImpl extends SSLEn
             // initial handshake has not been started yet
             return SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING;
         }
-        if (alertProtocol.hasAlert()) {
-            // need to send an alert
-            return SSLEngineResult.HandshakeStatus.NEED_WRAP;
-        }
-        if (close_notify_was_sent && !close_notify_was_received) {
-            // waiting for "close_notify" response
-            return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
-        }
-        return handshakeProtocol.getStatus();
+        return handshakeStatus;
+//        if (alertProtocol.hasAlert()) {
+//            // need to send an alert
+//            return SSLEngineResult.HandshakeStatus.NEED_WRAP;
+//        }
+//        if (close_notify_was_sent && !close_notify_was_received) {
+//            // waiting for "close_notify" response
+//            return SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+//        }
+//        return handshakeProtocol.getStatus();
     }
-
+    
     /**
      * This method works according to the specification of implemented class.
      * @see javax.net.ssl.SSLEngine#getSession() method
@@ -608,148 +631,155 @@ public class SSLEngineImpl extends SSLEn
         if (!handshake_started) {
             beginHandshake();
         }
-
-        SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
-        // If it is an initial handshake or connection closure stage,
-        // check if this call was made in spite of handshake status
-        if ((session == null || engine_was_closed) && (
-                handshakeStatus.equals(
-                        SSLEngineResult.HandshakeStatus.NEED_UNWRAP) ||
-                handshakeStatus.equals(
-                        SSLEngineResult.HandshakeStatus.NEED_TASK))) {
-            return new SSLEngineResult(
-                    getEngineStatus(), handshakeStatus, 0, 0);
-        }
-
-        int capacity = dst.remaining();
-        int produced = 0;
-
-        if (alertProtocol.hasAlert()) {
-            // we have an alert to be sent
-            if (capacity < recordProtocol.getRecordSize(2)) {
-                return new SSLEngineResult(
-                        SSLEngineResult.Status.BUFFER_OVERFLOW,
-                        handshakeStatus, 0, 0);
-            }
-            byte[] alert_data = alertProtocol.wrap();
-            // place the alert record into destination
-            dst.put(alert_data);
-            if (alertProtocol.isFatalAlert()) {
-                alertProtocol.setProcessed();
-                if (session != null) {
-                    session.invalidate();
-                }
-                // fatal alert has been sent, so shut down the engine
-                shutdown();
-                return new SSLEngineResult(
-                        SSLEngineResult.Status.CLOSED,
-                        SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
-                        0, alert_data.length);
-            } else {
-                alertProtocol.setProcessed();
-                // check if the works on this engine have been done
-                if (close_notify_was_sent && close_notify_was_received) {
-                    shutdown();
-                    return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
-                            SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
-                            0, alert_data.length);
-                }
-                return new SSLEngineResult(
-                        getEngineStatus(),
-                        getHandshakeStatus(),
-                        0, alert_data.length);
-            }
-        }
-
-        if (capacity < recordProtocol.getMinRecordSize()) {
-            if (logger != null) {
-                logger.println("Capacity of the destination("
-                        +capacity+") < MIN_PACKET_SIZE("
-                        +recordProtocol.getMinRecordSize()+")");
-            }
-            return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
-                        handshakeStatus, 0, 0);
-        }
-
-        try {
-            if (!handshakeStatus.equals(
-                        SSLEngineResult.HandshakeStatus.NEED_WRAP)) {
-                // so we wraps application data
-                dataStream.setSourceBuffers(srcs, offset, len);
-                if ((capacity < SSLRecordProtocol.MAX_SSL_PACKET_SIZE) &&
-                    (capacity < recordProtocol.getRecordSize(
-                                                 dataStream.available()))) {
-                    if (logger != null) {
-                        logger.println("The destination buffer("
-                                +capacity+") can not take the resulting packet("
-                                + recordProtocol.getRecordSize(
-                                    dataStream.available())+")");
-                    }
-                    return new SSLEngineResult(
-                            SSLEngineResult.Status.BUFFER_OVERFLOW,
-                            handshakeStatus, 0, 0);
-                }
-                if (remaining_wrapped_data == null) {
-                    remaining_wrapped_data =
-                        recordProtocol.wrap(ContentType.APPLICATION_DATA,
-                                dataStream);
-                }
-                if (capacity < remaining_wrapped_data.length) {
-                    // It should newer happen because we checked the destination
-                    // buffer size, but there is a possibility
-                    // (if dest buffer was filled outside)
-                    // so we just remember the data into remaining_wrapped_data
-                    // and will enclose it during the the next call
-                    return new SSLEngineResult(
-                            SSLEngineResult.Status.BUFFER_OVERFLOW,
-                            handshakeStatus, dataStream.consumed(), 0);
-                } else {
-                    dst.put(remaining_wrapped_data);
-                    produced = remaining_wrapped_data.length;
-                    remaining_wrapped_data = null;
-                    return new SSLEngineResult(getEngineStatus(), 
-                            handshakeStatus, dataStream.consumed(), produced);
-                }
-            } else {
-                if (remaining_hsh_data == null) {
-                    remaining_hsh_data = handshakeProtocol.wrap();
-                }
-                if (capacity < remaining_hsh_data.length) {
-                    // It should newer happen because we checked the destination
-                    // buffer size, but there is a possibility
-                    // (if dest buffer was filled outside)
-                    // so we just remember the data into remaining_hsh_data
-                    // and will enclose it during the the next call
-                    return new SSLEngineResult(
-                            SSLEngineResult.Status.BUFFER_OVERFLOW,
-                            handshakeStatus, 0, 0);
-                } else {
-                    dst.put(remaining_hsh_data);
-                    produced = remaining_hsh_data.length;
-                    remaining_hsh_data = null;
-
-                    handshakeStatus = handshakeProtocol.getStatus();
-                    if (handshakeStatus.equals(
-                            SSLEngineResult.HandshakeStatus.FINISHED)) {
-                        session = recordProtocol.getSession();
-                    }
-                }
-                return new SSLEngineResult(
-                        getEngineStatus(), getHandshakeStatus(), 0, produced);
-            }
-        } catch (AlertException e) {
-            // fatal alert occured
-            alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode());
-            engine_was_closed = true;
-            if (session != null) {
-                session.invalidate();
-            }
-            // shutdown work will be made after the alert will be sent
-            // to another peer (by wrap method)
-            throw e.getReason();
-        }
+        
+        // only use the first buffer at the moment
+        byte[] src = srcs[0].array();
+        int src_len = src.length;
+        
+        return wrapImpl(SSL, src, src_len, dst.array(), dst.array().length);
+        
+        
+//        SSLEngineResult.HandshakeStatus handshakeStatus = getHandshakeStatus();
+//        // If it is an initial handshake or connection closure stage,
+//        // check if this call was made in spite of handshake status
+//        if ((session == null || engine_was_closed) && (
+//                handshakeStatus.equals(
+//                        SSLEngineResult.HandshakeStatus.NEED_UNWRAP) ||
+//                handshakeStatus.equals(
+//                        SSLEngineResult.HandshakeStatus.NEED_TASK))) {
+//            return new SSLEngineResult(
+//                    getEngineStatus(), handshakeStatus, 0, 0);
+//        }
+//
+//        int capacity = dst.remaining();
+//        int produced = 0;
+//
+//        if (alertProtocol.hasAlert()) {
+//            // we have an alert to be sent
+//            if (capacity < recordProtocol.getRecordSize(2)) {
+//                return new SSLEngineResult(
+//                        SSLEngineResult.Status.BUFFER_OVERFLOW,
+//                        handshakeStatus, 0, 0);
+//            }
+//            byte[] alert_data = alertProtocol.wrap();
+//            // place the alert record into destination
+//            dst.put(alert_data);
+//            if (alertProtocol.isFatalAlert()) {
+//                alertProtocol.setProcessed();
+//                if (session != null) {
+//                    session.invalidate();
+//                }
+//                // fatal alert has been sent, so shut down the engine
+//                shutdown();
+//                return new SSLEngineResult(
+//                        SSLEngineResult.Status.CLOSED,
+//                        SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
+//                        0, alert_data.length);
+//            } else {
+//                alertProtocol.setProcessed();
+//                // check if the works on this engine have been done
+//                if (close_notify_was_sent && close_notify_was_received) {
+//                    shutdown();
+//                    return new SSLEngineResult(SSLEngineResult.Status.CLOSED,
+//                            SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING,
+//                            0, alert_data.length);
+//                }
+//                return new SSLEngineResult(
+//                        getEngineStatus(),
+//                        getHandshakeStatus(),
+//                        0, alert_data.length);
+//            }
+//        }
+//
+//        if (capacity < recordProtocol.getMinRecordSize()) {
+//            if (logger != null) {
+//                logger.println("Capacity of the destination("
+//                        +capacity+") < MIN_PACKET_SIZE("
+//                        +recordProtocol.getMinRecordSize()+")");
+//            }
+//            return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW,
+//                        handshakeStatus, 0, 0);
+//        }
+//
+//        try {
+//            if (!handshakeStatus.equals(
+//                        SSLEngineResult.HandshakeStatus.NEED_WRAP)) {
+//                // so we wraps application data
+//                dataStream.setSourceBuffers(srcs, offset, len);
+//                if ((capacity < SSLRecordProtocol.MAX_SSL_PACKET_SIZE) &&
+//                    (capacity < recordProtocol.getRecordSize(
+//                                                 dataStream.available()))) {
+//                    if (logger != null) {
+//                        logger.println("The destination buffer("
+//                                +capacity+") can not take the resulting packet("
+//                                + recordProtocol.getRecordSize(
+//                                    dataStream.available())+")");
+//                    }
+//                    return new SSLEngineResult(
+//                            SSLEngineResult.Status.BUFFER_OVERFLOW,
+//                            handshakeStatus, 0, 0);
+//                }
+//                if (remaining_wrapped_data == null) {
+//                    remaining_wrapped_data =
+//                        recordProtocol.wrap(ContentType.APPLICATION_DATA,
+//                                dataStream);
+//                }
+//                if (capacity < remaining_wrapped_data.length) {
+//                    // It should newer happen because we checked the destination
+//                    // buffer size, but there is a possibility
+//                    // (if dest buffer was filled outside)
+//                    // so we just remember the data into remaining_wrapped_data
+//                    // and will enclose it during the the next call
+//                    return new SSLEngineResult(
+//                            SSLEngineResult.Status.BUFFER_OVERFLOW,
+//                            handshakeStatus, dataStream.consumed(), 0);
+//                } else {
+//                    dst.put(remaining_wrapped_data);
+//                    produced = remaining_wrapped_data.length;
+//                    remaining_wrapped_data = null;
+//                    return new SSLEngineResult(getEngineStatus(), 
+//                            handshakeStatus, dataStream.consumed(), produced);
+//                }
+//            } else {
+//                if (remaining_hsh_data == null) {
+//                    remaining_hsh_data = handshakeProtocol.wrap();
+//                }
+//                if (capacity < remaining_hsh_data.length) {
+//                    // It should newer happen because we checked the destination
+//                    // buffer size, but there is a possibility
+//                    // (if dest buffer was filled outside)
+//                    // so we just remember the data into remaining_hsh_data
+//                    // and will enclose it during the the next call
+//                    return new SSLEngineResult(
+//                            SSLEngineResult.Status.BUFFER_OVERFLOW,
+//                            handshakeStatus, 0, 0);
+//                } else {
+//                    dst.put(remaining_hsh_data);
+//                    produced = remaining_hsh_data.length;
+//                    remaining_hsh_data = null;
+//
+//                    handshakeStatus = handshakeProtocol.getStatus();
+//                    if (handshakeStatus.equals(
+//                            SSLEngineResult.HandshakeStatus.FINISHED)) {
+//                        session = recordProtocol.getSession();
+//                    }
+//                }
+//                return new SSLEngineResult(
+//                        getEngineStatus(), getHandshakeStatus(), 0, produced);
+//            }
+//        } catch (AlertException e) {
+//            // fatal alert occured
+//            alertProtocol.alert(AlertProtocol.FATAL, e.getDescriptionCode());
+//            engine_was_closed = true;
+//            if (session != null) {
+//                session.invalidate();
+//            }
+//            // shutdown work will be made after the alert will be sent
+//            // to another peer (by wrap method)
+//            throw e.getReason();
+//        }
     }
-
+    
     // Shutdownes the engine and makes all cleanup work.
     private void shutdown() {
         engine_was_closed = true;

Modified: harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.c
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.c?rev=995839&r1=995838&r2=995839&view=diff
==============================================================================
--- harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.c (original)
+++ harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.c Fri Sep 10 16:01:18 2010
@@ -24,9 +24,167 @@
 #include "openssl/ssl.h"
 #include "openssl/err.h"
 
+static jobject handshake_need_wrap, handshake_need_unwrap, handshake_finished, handshake_not_handshaking;
+static jobject engine_buffer_overflow, engine_buffer_underflow, engine_closed, engine_ok;
+static int initialised = 0;
+
+void init(JNIEnv *env) {
+    jclass class;
+    jfieldID fieldID;
+    if (initialised == 1) {
+      return;
+    }
+    // initialise handshake status enum
+    class = (*env)->FindClass(env, "javax/net/ssl/SSLEngineResult$HandshakeStatus");
+    fieldID = (*env)->GetStaticFieldID(env, class, "NEED_WRAP", "Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;");
+    handshake_need_wrap = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    fieldID = (*env)->GetStaticFieldID(env, class, "NEED_UNWRAP", "Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;");
+    handshake_need_unwrap = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    fieldID = (*env)->GetStaticFieldID(env, class, "FINISHED", "Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;");
+    handshake_finished = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    fieldID = (*env)->GetStaticFieldID(env, class, "NOT_HANDSHAKING", "Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;");
+    handshake_not_handshaking = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    
+    // initialise engine status enum
+    class = (*env)->FindClass(env, "javax/net/ssl/SSLEngineResult$Status");
+    fieldID = (*env)->GetStaticFieldID(env, class, "BUFFER_OVERFLOW", "Ljavax/net/ssl/SSLEngineResult$Status;");
+    engine_buffer_overflow = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    fieldID = (*env)->GetStaticFieldID(env, class, "BUFFER_UNDERFLOW", "Ljavax/net/ssl/SSLEngineResult$Status;");
+    engine_buffer_underflow = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    fieldID = (*env)->GetStaticFieldID(env, class, "CLOSED", "Ljavax/net/ssl/SSLEngineResult$Status;");
+    engine_closed = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    fieldID = (*env)->GetStaticFieldID(env, class, "OK", "Ljavax/net/ssl/SSLEngineResult$Status;");
+    engine_ok = (*env)->NewGlobalRef(env, (*env)->GetStaticObjectField(env, class, fieldID));
+    
+    initialised = 1;
+}
+
+jobject getHandshakeStatus(JNIEnv *env, int state) {
+    jclass exception;
+    switch(state) {
+    case SSL_ERROR_NONE:
+      return handshake_not_handshaking;
+    case SSL_ERROR_WANT_READ:
+      return handshake_need_unwrap;
+    case SSL_ERROR_WANT_WRITE:
+      return handshake_need_wrap;
+    default:
+      exception = (*env)->FindClass(env, "javax/net/ssl/SSLHandshakeException");
+      (*env)->ThrowNew(env, exception, ERR_reason_error_string(ERR_get_error()));
+    }
+    return NULL;
+}
 
 JNIEXPORT jlong JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_initImpl
   (JNIEnv *env, jclass clazz, jlong context) {
+    init(env);
     return addr2jlong(SSL_new(jlong2addr(SSL_CTX, context)));
 }
 
+JNIEXPORT jobject JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_acceptImpl
+  (JNIEnv *env, jclass clazz, jlong jssl) {
+    SSL *ssl = jlong2addr(SSL, jssl);
+    BIO *server, *server_out;
+    int ret;
+    size_t bufsiz = 256;
+
+    // create a bio pair
+    BIO_new_bio_pair(&server, bufsiz, &server_out, bufsiz);
+    
+    SSL_set_bio(ssl, server, server);
+
+    // Put our SSL into connect state
+    SSL_set_accept_state(ssl);
+
+    // Start the client handshake
+    ret = SSL_do_handshake(ssl);
+
+    return getHandshakeStatus(env, SSL_get_error(ssl, ret));
+}
+
+JNIEXPORT jobject JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_connectImpl
+  (JNIEnv *env, jclass clazz, jlong jssl) {
+    SSL *ssl = jlong2addr(SSL, jssl);
+    BIO *client, *client_out;
+    int ret;
+    
+    size_t bufsize = 256;  // need to fix
+
+    // create a bio pair
+    BIO_new_bio_pair(&client, bufsize, &client_out, bufsize);
+    
+    SSL_set_bio(ssl, client, client);
+
+    // Put our SSL into connect state
+    SSL_set_connect_state(ssl);
+
+    // Start the client handshake
+    ret = SSL_do_handshake(ssl);
+
+    return getHandshakeStatus(env, SSL_get_error(ssl, ret));
+}
+
+JNIEXPORT jobject JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_wrapImpl
+  (JNIEnv *env, jclass clazz, jlong jssl, jbyteArray src, int src_len, 
+  jbyteArray dst, int dst_len) {
+    SSL *ssl = jlong2addr(SSL, jssl);
+    int write_result, read_result;
+    jobject handshake_state, engine_state, result;
+    jclass result_class;
+    jmethodID result_constructor;
+
+    // write input data
+    jbyte *buffer = (jbyte*) malloc(src_len * sizeof(jbyte*)); 
+    (*env)->GetByteArrayRegion(env, src, 0, src_len, buffer);
+
+    write_result = SSL_write(ssl, (const void *)buffer, (int)src_len);
+    fprintf(stderr, "SSL_write, result:%d \n", write_result);
+    if (write_result > 0) {
+        // must not be handshaking as we've written bytes
+        handshake_state = handshake_not_handshaking;
+        if (write_result < src_len) {
+            engine_state = engine_buffer_overflow;
+        } else {
+            engine_state = engine_ok;
+        }
+    } if (write_result == 0) {
+        handshake_state = handshake_not_handshaking;
+        engine_state = engine_closed;
+    } else {
+        handshake_state = getHandshakeStatus(env, SSL_get_error(ssl, write_result));
+        if ((*env)->ExceptionCheck(env)) {
+            return NULL;
+        }
+        engine_state = engine_ok; // is this correct?
+        write_result = 0;
+    }
+    free(buffer);
+    
+    
+    // read output data
+    buffer = (jbyte*) malloc(dst_len * sizeof(jbyte*));
+
+    read_result = SSL_read(ssl, (void *)buffer, (int)dst_len);
+    if (read_result > 0) {
+      (*env)->SetByteArrayRegion(env, dst, 0, read_result, buffer);
+    }
+    if (read_result == -1) {
+        // The socket has been closed
+        jclass exception = (*env)->FindClass(env, "java/net/SocketException");
+        (*env)->ThrowNew(env, exception, "Connection was reset");
+        return NULL;
+    }
+    if (read_result < 0) {
+      fprintf(stderr, "Read returned:%d \n", read_result);
+      read_result = 0;
+    }
+    free(buffer);
+    
+    // construct return object
+    result_class = (*env)->FindClass(env, "javax/net/ssl/SSLEngineResult");
+    result_constructor = (*env)->GetMethodID(env, result_class, "<init>", 
+        "(Ljavax/net/ssl/SSLEngineResult$Status;Ljavax/net/ssl/SSLEngineResult$HandshakeStatus;II)V");
+    result = (*env)->NewObject(env, result_class, result_constructor,
+        engine_state, handshake_state, write_result, read_result);
+    return result;
+}

Modified: harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.h
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.h?rev=995839&r1=995838&r2=995839&view=diff
==============================================================================
--- harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.h (original)
+++ harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/shared/sslEngine.h Fri Sep 10 16:01:18 2010
@@ -25,7 +25,12 @@ extern "C" {
 
 JNIEXPORT jlong JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_initImpl
   (JNIEnv *, jclass, jlong);
-
+JNIEXPORT jobject JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_acceptImpl
+  (JNIEnv *, jclass, jlong);
+JNIEXPORT jobject JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_connectImpl
+  (JNIEnv *, jclass, jlong);
+JNIEXPORT jobject JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_wrapImpl
+  (JNIEnv *, jclass, jlong, jbyteArray, int, jbyteArray, int);
 #ifdef __cplusplus
 }
 #endif

Modified: harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/unix/exports.txt
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/unix/exports.txt?rev=995839&r1=995838&r2=995839&view=diff
==============================================================================
--- harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/unix/exports.txt (original)
+++ harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/main/native/jsse/unix/exports.txt Fri Sep 10 16:01:18 2010
@@ -14,3 +14,6 @@ Java_org_apache_harmony_xnet_provider_js
 Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_readAppDataImpl
 Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_closeImpl
 Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_initImpl
+Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_acceptImpl
+Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_connectImpl
+Java_org_apache_harmony_xnet_provider_jsse_SSLEngineImpl_wrapImpl

Modified: harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/test/api/java/org/apache/harmony/xnet/tests/javax/net/ssl/SSLEngineTest.java
URL: http://svn.apache.org/viewvc/harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/test/api/java/org/apache/harmony/xnet/tests/javax/net/ssl/SSLEngineTest.java?rev=995839&r1=995838&r2=995839&view=diff
==============================================================================
--- harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/test/api/java/org/apache/harmony/xnet/tests/javax/net/ssl/SSLEngineTest.java (original)
+++ harmony/enhanced/java/branches/omd/classlib/modules/x-net/src/test/api/java/org/apache/harmony/xnet/tests/javax/net/ssl/SSLEngineTest.java Fri Sep 10 16:01:18 2010
@@ -18,14 +18,15 @@
 package org.apache.harmony.xnet.tests.javax.net.ssl;
 
 import java.nio.ByteBuffer;
-import java.nio.ReadOnlyBufferException;
-
+import javax.net.ssl.SSLContext;
 import javax.net.ssl.SSLEngine;
 import javax.net.ssl.SSLException;
 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
 import javax.net.ssl.SSLSession;
 import javax.net.ssl.SSLEngineResult;
 
+import org.apache.harmony.xnet.provider.jsse.JSSETestData;
+
 import junit.framework.TestCase;
 
 /**
@@ -344,6 +345,94 @@ public class SSLEngineTest extends TestC
         assertEquals(1, res.bytesConsumed());
         assertEquals(2, res.bytesProduced());
     }
+    
+    /**
+     * Test for <code>beginHandshake()</code> method
+     * 
+     * Test establishing a handshake between client and server and then sending
+     * some data between them.
+     */
+    public void testHandshake() throws Exception {
+        SSLContext context = JSSETestData.getContext();
+        SSLEngine client = context.createSSLEngine();
+        client.setUseClientMode(true);
+        client.beginHandshake();
+        assertEquals(HandshakeStatus.NEED_WRAP, client.getHandshakeStatus());
+        SSLEngine server = context.createSSLEngine();
+        server.setUseClientMode(false);
+        server.beginHandshake();
+        assertEquals(HandshakeStatus.NEED_UNWRAP, server.getHandshakeStatus());
+
+        // application data
+        String clientData = "hello server";
+        String serverData = "hello client";
+
+        // create buffers
+        // output buffers contain the application data to write
+        ByteBuffer clientOutBuffer = ByteBuffer.wrap(clientData.getBytes());
+        ByteBuffer serverOutBuffer = ByteBuffer.wrap(serverData.getBytes());
+        // input buffers contain the responses to read
+        ByteBuffer clientInBuffer = ByteBuffer.allocate(client.getSession()
+                .getApplicationBufferSize());
+        ByteBuffer serverInBuffer = ByteBuffer.allocate(server.getSession()
+                .getApplicationBufferSize());
+        // transport buffers represent the network connection
+        ByteBuffer clientTransport = ByteBuffer.allocate(client.getSession()
+                .getPacketBufferSize());
+        ByteBuffer serverTransport = ByteBuffer.allocate(server.getSession()
+                .getPacketBufferSize());
+
+        SSLEngineResult result;
+        // loop trying to establish handshake between server and client
+        // break out when the application data has been written
+        while (true) {
+            // first try writing from the server/client to the transport
+            result = server.wrap(serverOutBuffer, serverTransport);
+            if (server.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable task = server.getDelegatedTask();
+                task.run();
+            }
+            result = client.wrap(clientOutBuffer, clientTransport);
+            if (client.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable task = client.getDelegatedTask();
+                task.run();
+            }
+            
+            // then read from the transport to the server/client
+            serverTransport.flip();
+            clientTransport.flip();
+            result = server.unwrap(clientTransport, serverInBuffer);
+            if (server.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable task = server.getDelegatedTask();
+                task.run();
+            }
+            result = client.unwrap(serverTransport, clientInBuffer);
+            if (client.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
+                Runnable task = client.getDelegatedTask();
+                task.run();
+            }
+
+            // clear the buffers
+            serverTransport.clear();
+            clientTransport.clear();
+
+            // if all application data bas been written, break out
+            if (clientOutBuffer.remaining() == 0
+                    && serverOutBuffer.remaining() == 0) {
+                break;
+            }
+        }
+        // check that the handshake status is correct
+        assertEquals(HandshakeStatus.NOT_HANDSHAKING, client
+                .getHandshakeStatus());
+        assertEquals(HandshakeStatus.NOT_HANDSHAKING, server
+                .getHandshakeStatus());
+        // check the data in the client and server buffers
+        assertEquals(clientData, new String(serverInBuffer.array(), 0,
+                clientData.length()));
+        assertEquals(serverData, new String(clientInBuffer.array(), 0,
+                serverData.length()));
+    }
 }
 
 /*