OSDN Git Service

Merge commit 'a0a3ad10' into manualmerge
[android-x86/dalvik.git] / libcore / x-net / src / main / native / org_apache_harmony_xnet_provider_jsse_NativeCrypto.cpp
index d0682a4..8af33aa 100644 (file)
@@ -46,7 +46,7 @@ struct jsse_ssl_app_data_t {
 
 /**
  * Frees the SSL error state.
- * 
+ *
  * OpenSSL keeps an "error stack" per thread, and given that this code
  * can be called from arbitrary threads that we don't keep track of,
  * we err on the side of freeing the error state promptly (instead of,
@@ -60,7 +60,7 @@ static void freeSslErrorState(void) {
 /*
  * Checks this thread's OpenSSL error queue and throws a RuntimeException if
  * necessary.
- * 
+ *
  * @return 1 if an exception was thrown, 0 if not.
  */
 static int throwExceptionIfNecessary(JNIEnv* env) {
@@ -79,13 +79,166 @@ static int throwExceptionIfNecessary(JNIEnv* env) {
     return result;
 }
 
+
+/**
+ * Throws an SocketTimeoutException with the given string as a message.
+ */
+static void throwSocketTimeoutException(JNIEnv* env, const char* message) {
+    if (jniThrowException(env, "java/net/SocketTimeoutException", message)) {
+        LOGE("Unable to throw");
+    }
+}
+
+/**
+ * Throws a java.io.IOException with the given string as a message.
+ */
+static void throwIOExceptionStr(JNIEnv* env, const char* message) {
+    if (jniThrowException(env, "java/io/IOException", message)) {
+        LOGE("Unable to throw");
+    }
+}
+
+/**
+ * Throws an IOException with a message constructed from the current
+ * SSL errors. This will also log the errors.
+ *
+ * @param env the JNI environment
+ * @param sslReturnCode return code from failing SSL function
+ * @param sslErrorCode error code returned from SSL_get_error()
+ * @param message null-ok; general error message
+ */
+static void throwIOExceptionWithSslErrors(JNIEnv* env, int sslReturnCode,
+        int sslErrorCode, const char* message) {
+    const char* messageStr = NULL;
+    char* str;
+    int ret;
+
+    // First consult the SSL error code for the general message.
+    switch (sslErrorCode) {
+        case SSL_ERROR_NONE:
+            messageStr = "Ok";
+            break;
+        case SSL_ERROR_SSL:
+            messageStr = "Failure in SSL library, usually a protocol error";
+            break;
+        case SSL_ERROR_WANT_READ:
+            messageStr = "SSL_ERROR_WANT_READ occured. You should never see this.";
+            break;
+        case SSL_ERROR_WANT_WRITE:
+            messageStr = "SSL_ERROR_WANT_WRITE occured. You should never see this.";
+            break;
+        case SSL_ERROR_WANT_X509_LOOKUP:
+            messageStr = "SSL_ERROR_WANT_X509_LOOKUP occured. You should never see this.";
+            break;
+        case SSL_ERROR_SYSCALL:
+            messageStr = "I/O error during system call";
+            break;
+        case SSL_ERROR_ZERO_RETURN:
+            messageStr = "SSL_ERROR_ZERO_RETURN occured. You should never see this.";
+            break;
+        case SSL_ERROR_WANT_CONNECT:
+            messageStr = "SSL_ERROR_WANT_CONNECT occured. You should never see this.";
+            break;
+        case SSL_ERROR_WANT_ACCEPT:
+            messageStr = "SSL_ERROR_WANT_ACCEPT occured. You should never see this.";
+            break;
+        default:
+            messageStr = "Unknown SSL error";
+    }
+
+    // Prepend either our explicit message or a default one.
+    if (asprintf(&str, "%s: %s",
+            (message != NULL) ? message : "SSL error", messageStr) == 0) {
+        throwIOExceptionStr(env, messageStr);
+        LOGV("%s", messageStr);
+        freeSslErrorState();
+        return;
+    }
+
+    char* allocStr = str;
+
+    // For SSL protocol errors, SSL might have more information.
+    if (sslErrorCode == SSL_ERROR_SSL) {
+        // Append each error as an additional line to the message.
+        for (;;) {
+            char errStr[256];
+            const char* file;
+            int line;
+            const char* data;
+            int flags;
+            unsigned long err =
+                ERR_get_error_line_data(&file, &line, &data, &flags);
+            if (err == 0) {
+                break;
+            }
+
+            ERR_error_string_n(err, errStr, sizeof(errStr));
+
+            ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
+                    (allocStr == NULL) ? "" : allocStr,
+                    errStr,
+                    file,
+                    line,
+                    data,
+                    flags);
+
+            if (ret < 0) {
+                break;
+            }
+
+            free(allocStr);
+            allocStr = str;
+        }
+    // For errors during system calls, errno might be our friend.
+    } else if (sslErrorCode == SSL_ERROR_SYSCALL) {
+        if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
+            free(allocStr);
+            allocStr = str;
+        }
+    // If the error code is invalid, print it.
+    } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
+        if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
+            free(allocStr);
+            allocStr = str;
+        }
+    }
+
+    throwIOExceptionStr(env, allocStr);
+
+    LOGV("%s", allocStr);
+    free(allocStr);
+    freeSslErrorState();
+}
+
+/**
+ * Helper function that grabs the casts an ssl pointer and then checks for nullness.
+ * If this function returns NULL and <code>throwIfNull</code> is
+ * passed as <code>true</code>, then this function will call
+ * <code>throwIOExceptionStr</code> before returning, so in this case of
+ * NULL, a caller of this function should simply return and allow JNI
+ * to do its thing.
+ *
+ * @param env the JNI environment
+ * @param ssl_address; the ssl_address pointer as an integer
+ * @param throwIfNull whether to throw if the SSL pointer is NULL
+ * @returns the pointer, which may be NULL
+ */
+static SSL* getSslPointer(JNIEnv* env, int ssl_address, bool throwIfNull) {
+    SSL* ssl = reinterpret_cast<SSL*>(static_cast<uintptr_t>(ssl_address));
+    if ((ssl == NULL) && throwIfNull) {
+        throwIOExceptionStr(env, "null SSL pointer");
+    }
+
+    return ssl;
+}
+
 /**
  * Converts a Java byte[] to an OpenSSL BIGNUM, allocating the BIGNUM on the
  * fly.
  */
 static BIGNUM* arrayToBignum(JNIEnv* env, jbyteArray source) {
     // LOGD("Entering arrayToBignum()");
-  
+
     jbyte* sourceBytes = env->GetByteArrayElements(source, NULL);
     int sourceLength = env->GetArrayLength(source);
     BIGNUM* bignum = BN_bin2bn((unsigned char*) sourceBytes, sourceLength, NULL);
@@ -94,18 +247,98 @@ static BIGNUM* arrayToBignum(JNIEnv* env, jbyteArray source) {
 }
 
 /**
- * private static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g, byte[] pub_key, byte[] priv_key);
+ * OpenSSL locking support. Taken from the O'Reilly book by Viega et al., but I
+ * suppose there are not many other ways to do this on a Linux system (modulo
+ * isomorphism).
+ */
+#define MUTEX_TYPE pthread_mutex_t
+#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
+#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
+#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
+#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
+#define THREAD_ID pthread_self()
+#define THROW_EXCEPTION (-2)
+#define THROW_SOCKETTIMEOUTEXCEPTION (-3)
+
+static MUTEX_TYPE *mutex_buf = NULL;
+
+static void locking_function(int mode, int n, const char * file, int line) {
+    if (mode & CRYPTO_LOCK) {
+        MUTEX_LOCK(mutex_buf[n]);
+    } else {
+        MUTEX_UNLOCK(mutex_buf[n]);
+    }
+}
+
+static unsigned long id_function(void) {
+    return ((unsigned long)THREAD_ID);
+}
+
+int THREAD_setup(void) {
+    int i;
+
+    mutex_buf = (MUTEX_TYPE *)malloc(CRYPTO_num_locks( ) * sizeof(MUTEX_TYPE));
+
+    if(!mutex_buf) {
+        return 0;
+    }
+
+    for (i = 0; i < CRYPTO_num_locks( ); i++) {
+        MUTEX_SETUP(mutex_buf[i]);
+    }
+
+    CRYPTO_set_id_callback(id_function);
+    CRYPTO_set_locking_callback(locking_function);
+
+    return 1;
+}
+
+int THREAD_cleanup(void) {
+    int i;
+
+    if (!mutex_buf) {
+      return 0;
+    }
+
+    CRYPTO_set_id_callback(NULL);
+    CRYPTO_set_locking_callback(NULL);
+
+    for (i = 0; i < CRYPTO_num_locks( ); i++) {
+        MUTEX_CLEANUP(mutex_buf[i]);
+    }
+
+    free(mutex_buf);
+    mutex_buf = NULL;
+
+    return 1;
+}
+
+/**
+ * Initialization phase for every OpenSSL job: Loads the Error strings, the
+ * crypto algorithms and reset the OpenSSL library
+ */
+static void NativeCrypto_clinit(JNIEnv* env, jclass)
+{
+    SSL_load_error_strings();
+    ERR_load_crypto_strings();
+    SSL_library_init();
+    OpenSSL_add_all_algorithms();
+    THREAD_setup();
+}
+
+/**
+ * public static native int EVP_PKEY_new_DSA(byte[] p, byte[] q, byte[] g, byte[] pub_key, byte[] priv_key);
  */
 static EVP_PKEY* NativeCrypto_EVP_PKEY_new_DSA(JNIEnv* env, jclass clazz, jbyteArray p, jbyteArray q, jbyteArray g, jbyteArray pub_key, jbyteArray priv_key) {
     // LOGD("Entering EVP_PKEY_new_DSA()");
-  
+
     DSA* dsa = DSA_new();
-  
+
     dsa->p = arrayToBignum(env, p);
     dsa->q = arrayToBignum(env, q);
     dsa->g = arrayToBignum(env, g);
     dsa->pub_key = arrayToBignum(env, pub_key);
-    
+
     if (priv_key != NULL) {
         dsa->priv_key = arrayToBignum(env, priv_key);
     }
@@ -115,10 +348,10 @@ static EVP_PKEY* NativeCrypto_EVP_PKEY_new_DSA(JNIEnv* env, jclass clazz, jbyteA
         jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
         return NULL;
     }
-    
+
     EVP_PKEY* pkey = EVP_PKEY_new();
     EVP_PKEY_assign_DSA(pkey, dsa);
-    
+
     return pkey;
 }
 
@@ -127,36 +360,36 @@ static EVP_PKEY* NativeCrypto_EVP_PKEY_new_DSA(JNIEnv* env, jclass clazz, jbyteA
  */
 static EVP_PKEY* NativeCrypto_EVP_PKEY_new_RSA(JNIEnv* env, jclass clazz, jbyteArray n, jbyteArray e, jbyteArray d, jbyteArray p, jbyteArray q) {
     // LOGD("Entering EVP_PKEY_new_RSA()");
-  
+
     RSA* rsa = RSA_new();
-  
+
     rsa->n = arrayToBignum(env, n);
     rsa->e = arrayToBignum(env, e);
-    
+
     if (d != NULL) {
         rsa->d = arrayToBignum(env, d);
     }
-    
+
     if (p != NULL) {
         rsa->p = arrayToBignum(env, p);
     }
-    
+
     if (q != NULL) {
         rsa->q = arrayToBignum(env, q);
     }
 
     // int check = RSA_check_key(rsa);
     // LOGI("RSA_check_key returns %d", check);
-    
+
     if (rsa->n == NULL || rsa->e == NULL) {
         RSA_free(rsa);
         jniThrowRuntimeException(env, "Unable to convert BigInteger to BIGNUM");
         return NULL;
     }
-    
+
     EVP_PKEY* pkey = EVP_PKEY_new();
     EVP_PKEY_assign_RSA(pkey, rsa);
-    
+
     return pkey;
 }
 
@@ -176,7 +409,7 @@ static void NativeCrypto_EVP_PKEY_free(JNIEnv* env, jclass clazz, EVP_PKEY* pkey
  */
 static jint NativeCrypto_EVP_new(JNIEnv* env, jclass clazz) {
     // LOGI("NativeCrypto_EVP_DigestNew");
-    
+
     return (jint)EVP_MD_CTX_create();
 }
 
@@ -185,7 +418,7 @@ static jint NativeCrypto_EVP_new(JNIEnv* env, jclass clazz) {
  */
 static void NativeCrypto_EVP_free(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx) {
     // LOGI("NativeCrypto_EVP_DigestFree");
-  
+
     if (ctx != NULL) {
         EVP_MD_CTX_destroy(ctx);
     }
@@ -196,20 +429,20 @@ static void NativeCrypto_EVP_free(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx) {
  */
 static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx, jbyteArray hash, jint offset) {
     // LOGI("NativeCrypto_EVP_DigestFinal%x, %x, %d, %d", ctx, hash, offset);
-    
+
     if (ctx == NULL || hash == NULL) {
         jniThrowNullPointerException(env, NULL);
         return -1;
     }
 
     int result = -1;
-    
+
     jbyte* hashBytes = env->GetByteArrayElements(hash, NULL);
     EVP_DigestFinal(ctx, (unsigned char*) (hashBytes + offset), (unsigned int*)&result);
     env->ReleaseByteArrayElements(hash, hashBytes, 0);
 
     throwExceptionIfNecessary(env);
-    
+
     return result;
 }
 
@@ -218,24 +451,24 @@ static jint NativeCrypto_EVP_DigestFinal(JNIEnv* env, jclass clazz, EVP_MD_CTX*
  */
 static void NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx, jstring algorithm) {
     // LOGI("NativeCrypto_EVP_DigestInit");
-    
+
     if (ctx == NULL || algorithm == NULL) {
         jniThrowNullPointerException(env, NULL);
         return;
     }
-    
+
     const char* algorithmChars = env->GetStringUTFChars(algorithm, NULL);
-    
+
     const EVP_MD *digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars));
     env->ReleaseStringUTFChars(algorithm, algorithmChars);
-    
+
     if (digest == NULL) {
         jniThrowRuntimeException(env, "Hash algorithm not found");
         return;
     }
-    
+
     EVP_DigestInit(ctx, digest);
-    
+
     throwExceptionIfNecessary(env);
 }
 
@@ -244,16 +477,16 @@ static void NativeCrypto_EVP_DigestInit(JNIEnv* env, jclass clazz, EVP_MD_CTX* c
  */
 static jint NativeCrypto_EVP_DigestSize(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx) {
     // LOGI("NativeCrypto_EVP_DigestSize");
-    
+
     if (ctx == NULL) {
         jniThrowNullPointerException(env, NULL);
         return -1;
     }
-    
+
     int result = EVP_MD_CTX_size(ctx);
-    
+
     throwExceptionIfNecessary(env);
-    
+
     return result;
 }
 
@@ -262,16 +495,16 @@ static jint NativeCrypto_EVP_DigestSize(JNIEnv* env, jclass clazz, EVP_MD_CTX* c
  */
 static jint NativeCrypto_EVP_DigestBlockSize(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx) {
     // LOGI("NativeCrypto_EVP_DigestBlockSize");
-    
+
     if (ctx == NULL) {
         jniThrowNullPointerException(env, NULL);
         return -1;
     }
-    
+
     int result = EVP_MD_CTX_block_size(ctx);
-    
+
     throwExceptionIfNecessary(env);
-    
+
     return result;
 }
 
@@ -280,16 +513,16 @@ static jint NativeCrypto_EVP_DigestBlockSize(JNIEnv* env, jclass clazz, EVP_MD_C
  */
 static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx, jbyteArray buffer, jint offset, jint length) {
     // LOGI("NativeCrypto_EVP_DigestUpdate %x, %x, %d, %d", ctx, buffer, offset, length);
-    
+
     if (ctx == NULL || buffer == NULL) {
         jniThrowNullPointerException(env, NULL);
         return;
     }
-  
+
     jbyte* bufferBytes = env->GetByteArrayElements(buffer, NULL);
     EVP_DigestUpdate(ctx, (unsigned char*) (bufferBytes + offset), length);
     env->ReleaseByteArrayElements(buffer, bufferBytes, JNI_ABORT);
-  
+
     throwExceptionIfNecessary(env);
 }
 
@@ -298,24 +531,24 @@ static void NativeCrypto_EVP_DigestUpdate(JNIEnv* env, jclass clazz, EVP_MD_CTX*
  */
 static void NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx, jstring algorithm) {
     // LOGI("NativeCrypto_EVP_VerifyInit");
-    
+
     if (ctx == NULL || algorithm == NULL) {
         jniThrowNullPointerException(env, NULL);
         return;
     }
-    
+
     const char* algorithmChars = env->GetStringUTFChars(algorithm, NULL);
-    
+
     const EVP_MD *digest = EVP_get_digestbynid(OBJ_txt2nid(algorithmChars));
     env->ReleaseStringUTFChars(algorithm, algorithmChars);
-    
+
     if (digest == NULL) {
         jniThrowRuntimeException(env, "Hash algorithm not found");
         return;
     }
-    
+
     EVP_VerifyInit(ctx, digest);
-    
+
     throwExceptionIfNecessary(env);
 }
 
@@ -324,16 +557,16 @@ static void NativeCrypto_EVP_VerifyInit(JNIEnv* env, jclass clazz, EVP_MD_CTX* c
  */
 static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx, jbyteArray buffer, jint offset, jint length) {
     // LOGI("NativeCrypto_EVP_VerifyUpdate %x, %x, %d, %d", ctx, buffer, offset, length);
-    
+
     if (ctx == NULL || buffer == NULL) {
         jniThrowNullPointerException(env, NULL);
         return;
     }
-  
+
     jbyte* bufferBytes = env->GetByteArrayElements(buffer, NULL);
     EVP_VerifyUpdate(ctx, (unsigned char*) (bufferBytes + offset), length);
     env->ReleaseByteArrayElements(buffer, bufferBytes, JNI_ABORT);
-  
+
     throwExceptionIfNecessary(env);
 }
 
@@ -342,343 +575,349 @@ static void NativeCrypto_EVP_VerifyUpdate(JNIEnv* env, jclass clazz, EVP_MD_CTX*
  */
 static int NativeCrypto_EVP_VerifyFinal(JNIEnv* env, jclass clazz, EVP_MD_CTX* ctx, jbyteArray buffer, jint offset, jint length, EVP_PKEY* pkey) {
     // LOGI("NativeCrypto_EVP_VerifyFinal %x, %x, %d, %d %x", ctx, buffer, offset, length, pkey);
-    
+
     if (ctx == NULL || buffer == NULL || pkey == NULL) {
         jniThrowNullPointerException(env, NULL);
         return -1;
     }
-  
+
     jbyte* bufferBytes = env->GetByteArrayElements(buffer, NULL);
     int result = EVP_VerifyFinal(ctx, (unsigned char*) (bufferBytes + offset), length, pkey);
     env->ReleaseByteArrayElements(buffer, bufferBytes, JNI_ABORT);
-  
-    throwExceptionIfNecessary(env);
-    
-    return result;
-}
 
-/*
- * Defines the mapping from Java methods and their signatures
- * to native functions. Order is (1) Java name, (2) signature,
- * (3) pointer to C function.
- */
-static JNINativeMethod sNativeCryptoMethods[] = {
-    { "EVP_PKEY_new_DSA",    "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_DSA },
-    { "EVP_PKEY_new_RSA",    "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_RSA },
-    { "EVP_PKEY_free",       "(I)V",          (void*)NativeCrypto_EVP_PKEY_free },
-    { "EVP_new",             "()I",           (void*)NativeCrypto_EVP_new },
-    { "EVP_free",            "(I)V",          (void*)NativeCrypto_EVP_free },
-    { "EVP_DigestFinal",     "(I[BI)I",       (void*)NativeCrypto_EVP_DigestFinal },
-    { "EVP_DigestInit",      "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_DigestInit },
-    { "EVP_DigestBlockSize", "(I)I",          (void*)NativeCrypto_EVP_DigestBlockSize },
-    { "EVP_DigestSize",      "(I)I",          (void*)NativeCrypto_EVP_DigestSize },
-    { "EVP_DigestUpdate",    "(I[BII)V",      (void*)NativeCrypto_EVP_DigestUpdate },
-    { "EVP_VerifyInit",      "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_VerifyInit },
-    { "EVP_VerifyUpdate",    "(I[BII)V",      (void*)NativeCrypto_EVP_VerifyUpdate },
-    { "EVP_VerifyFinal",     "(I[BIII)I",     (void*)NativeCrypto_EVP_VerifyFinal }
-};
-
-/**
- * Module scope variables initialized during JNI registration.
- */
-static jfieldID field_Socket_ssl_ctx;
-static jfieldID field_Socket_ssl;
-static jfieldID field_FileDescriptor_descriptor;
-static jfieldID field_Socket_mImpl;
-static jfieldID field_Socket_mFD;
-static jfieldID field_Socket_timeout;
-
-/**
- * Gets the chars of a String object as a '\0'-terminated UTF-8 string,
- * stored in a freshly-allocated BIO memory buffer.
- */
-static BIO *stringToMemBuf(JNIEnv* env, jstring string) {
-    jsize byteCount = env->GetStringUTFLength(string);
-    LocalArray<1024> buf(byteCount + 1);
-    env->GetStringUTFRegion(string, 0, env->GetStringLength(string), &buf[0]);
+    throwExceptionIfNecessary(env);
 
-    BIO* result = BIO_new(BIO_s_mem());
-    BIO_puts(result, &buf[0]);
     return result;
 }
 
 /**
- * Throws an SocketTimeoutException with the given string as a message.
+ * Convert ssl version constant to string. Based on SSL_get_version
  */
-static void throwSocketTimeoutException(JNIEnv* env, const char* message) {
-    if (jniThrowException(env, "java/net/SocketTimeoutException", message)) {
-        LOGE("Unable to throw");
+static const char* get_ssl_version(int ssl_version) {
+    switch (ssl_version) {
+        // newest to oldest
+        case TLS1_VERSION: {
+          return SSL_TXT_TLSV1;
+        }
+        case SSL3_VERSION: {
+          return SSL_TXT_SSLV3;
+        }
+        case SSL2_VERSION: {
+          return SSL_TXT_SSLV2;
+        }
+        default: {
+          return "unknown";
+        }
     }
 }
 
 /**
- * Throws a java.io.IOException with the given string as a message.
+ * Convert content type constant to string.
  */
-static void throwIOExceptionStr(JNIEnv* env, const char* message) {
-    if (jniThrowException(env, "java/io/IOException", message)) {
-        LOGE("Unable to throw");
+static const char* get_content_type(int content_type) {
+    switch (content_type) {
+        case SSL3_RT_CHANGE_CIPHER_SPEC: {
+            return "SSL3_RT_CHANGE_CIPHER_SPEC";
+        }
+        case SSL3_RT_ALERT: {
+            return "SSL3_RT_ALERT";
+        }
+        case SSL3_RT_HANDSHAKE: {
+            return "SSL3_RT_HANDSHAKE";
+        }
+        case SSL3_RT_APPLICATION_DATA: {
+            return "SSL3_RT_APPLICATION_DATA";
+        }
+        default: {
+            LOGD("Unknown TLS/SSL content type %d", content_type);
+            return "<unknown>";
+        }
     }
 }
 
 /**
- * Throws an IOException with a message constructed from the current
- * SSL errors. This will also log the errors.
- * 
- * @param env the JNI environment
- * @param sslReturnCode return code from failing SSL function
- * @param sslErrorCode error code returned from SSL_get_error()
- * @param message null-ok; general error message
+ * Simple logging call back to show hand shake messages
  */
-static void throwIOExceptionWithSslErrors(JNIEnv* env, int sslReturnCode,
-        int sslErrorCode, const char* message) {
-    const char* messageStr = NULL;
-    char* str;
-    int ret;
-
-    // First consult the SSL error code for the general message. 
-    switch (sslErrorCode) {
-        case SSL_ERROR_NONE:
-            messageStr = "Ok";
-            break;
-        case SSL_ERROR_SSL:
-            messageStr = "Failure in SSL library, usually a protocol error";
-            break;
-        case SSL_ERROR_WANT_READ:
-            messageStr = "SSL_ERROR_WANT_READ occured. You should never see this.";
-            break;
-        case SSL_ERROR_WANT_WRITE:
-            messageStr = "SSL_ERROR_WANT_WRITE occured. You should never see this.";
-            break;
-        case SSL_ERROR_WANT_X509_LOOKUP:
-            messageStr = "SSL_ERROR_WANT_X509_LOOKUP occured. You should never see this.";
-            break;
-        case SSL_ERROR_SYSCALL:
-            messageStr = "I/O error during system call";
-            break;
-        case SSL_ERROR_ZERO_RETURN:
-            messageStr = "SSL_ERROR_ZERO_RETURN occured. You should never see this.";
-            break;
-        case SSL_ERROR_WANT_CONNECT:
-            messageStr = "SSL_ERROR_WANT_CONNECT occured. You should never see this.";
-            break;
-        case SSL_ERROR_WANT_ACCEPT:
-            messageStr = "SSL_ERROR_WANT_ACCEPT occured. You should never see this.";
-            break;
-        default:
-            messageStr = "Unknown SSL error";
-    }
-
-    // Prepend either our explicit message or a default one.
-    if (asprintf(&str, "%s: %s",
-            (message != NULL) ? message : "SSL error", messageStr) == 0) {
-        throwIOExceptionStr(env, messageStr);
-        LOGV("%s", messageStr);
-        freeSslErrorState();
-        return;
-    }
-
-    char* allocStr = str;
-
-    // For SSL protocol errors, SSL might have more information.
-    if (sslErrorCode == SSL_ERROR_SSL) {
-        // Append each error as an additional line to the message.
-        for (;;) {
-            char errStr[256];
-            const char* file;
-            int line;
-            const char* data;
-            int flags;
-            unsigned long err =
-                ERR_get_error_line_data(&file, &line, &data, &flags);
-            if (err == 0) {
-                break;
-            }
+static void ssl_msg_callback_LOG(int write_p, int ssl_version, int content_type,
+                                 const void *buf, size_t len, SSL* ssl, void* arg) {
+    LOGD("SSL %p %s %s %s %p %d %p",
+         ssl,
+         (write_p) ? "send" : "recv",
+         get_ssl_version(ssl_version),
+         get_content_type(content_type),
+         buf,
+         len,
+         arg);
+}
 
-            ERR_error_string_n(err, errStr, sizeof(errStr));
+/*
+ * public static native int SSL_CTX_new();
+ */
+static int NativeCrypto_SSL_CTX_new(JNIEnv* env, jclass clazz) {
+    SSL_CTX* sslCtx = SSL_CTX_new(SSLv23_method());
+    // Note: We explicitly do not allow SSLv2 to be used.
+    SSL_CTX_set_options(sslCtx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
 
-            ret = asprintf(&str, "%s\n%s (%s:%d %p:0x%08x)",
-                    (allocStr == NULL) ? "" : allocStr,
-                    errStr,
-                    file,
-                    line,
-                    data,
-                    flags);
+    int mode = SSL_CTX_get_mode(sslCtx);
+    /*
+     * Turn on "partial write" mode. This means that SSL_write() will
+     * behave like Posix write() and possibly return after only
+     * writing a partial buffer. Note: The alternative, perhaps
+     * surprisingly, is not that SSL_write() always does full writes
+     * but that it will force you to retry write calls having
+     * preserved the full state of the original call. (This is icky
+     * and undesirable.)
+     */
+    mode |= SSL_MODE_ENABLE_PARTIAL_WRITE;
+#if defined(SSL_MODE_SMALL_BUFFERS) /* not all SSL versions have this */
+    mode |= SSL_MODE_SMALL_BUFFERS;  /* lazily allocate record buffers; usually saves
+                                      * 44k over the default */
+#endif
+#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) /* not all SSL versions have this */
+    mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH;  /* enable sending of client data as soon as
+                                             * ClientCCS and ClientFinished are sent */
+#endif
+    SSL_CTX_set_mode(sslCtx, mode);
 
-            if (ret < 0) {
-                break;
-            }
+    // SSL_CTX_set_msg_callback(sslCtx, ssl_msg_callback_LOG); /* enable for handshake debug */
+    return (jint) sslCtx;
+}
 
-            free(allocStr);
-            allocStr = str;
-        }
-    // For errors during system calls, errno might be our friend.        
-    } else if (sslErrorCode == SSL_ERROR_SYSCALL) {
-        if (asprintf(&str, "%s, %s", allocStr, strerror(errno)) >= 0) {
-            free(allocStr);
-            allocStr = str;
-        }
-    // If the error code is invalid, print it.
-    } else if (sslErrorCode > SSL_ERROR_WANT_ACCEPT) {
-        if (asprintf(&str, ", error code is %d", sslErrorCode) >= 0) {
-            free(allocStr);
-            allocStr = str;
-        }
+static jobjectArray makeCipherList(JNIEnv* env, STACK_OF(SSL_CIPHER)* cipher_list) {
+    // Create a String[].
+    jclass stringClass = env->FindClass("java/lang/String");
+    if (stringClass == NULL) {
+        return NULL;
+    }
+    int cipherCount = sk_SSL_CIPHER_num(cipher_list);
+    jobjectArray array = env->NewObjectArray(cipherCount, stringClass, NULL);
+    if (array == NULL) {
+        return NULL;
     }
 
-    throwIOExceptionStr(env, allocStr);
-
-    LOGV("%s", allocStr);
-    free(allocStr);
-    freeSslErrorState();
+    // Fill in the cipher names.
+    for (int i = 0; i < cipherCount; ++i) {
+        const char* c = sk_SSL_CIPHER_value(cipher_list, i)->name;
+        env->SetObjectArrayElement(array, i, env->NewStringUTF(c));
+    }
+    return array;
 }
 
 /**
- * Helper function that grabs the ssl pointer out of the given object.
- * If this function returns NULL and <code>throwIfNull</code> is
- * passed as <code>true</code>, then this function will call
- * <code>throwIOExceptionStr</code> before returning, so in this case of
- * NULL, a caller of this function should simply return and allow JNI
- * to do its thing.
- * 
- * @param env non-null; the JNI environment
- * @param obj non-null; socket object
- * @param throwIfNull whether to throw if the SSL pointer is NULL
- * @returns the pointer, which may be NULL
+ * Loads the ciphers suites that are supported by an SSL_CTX
+ * and returns them in a string array.
  */
-static SSL *getSslPointer(JNIEnv* env, jobject obj, bool throwIfNull) {
-    SSL *ssl = (SSL *)env->GetIntField(obj, field_Socket_ssl);
-
-    if ((ssl == NULL) && throwIfNull) {
-        throwIOExceptionStr(env, "null SSL pointer");
+static jobjectArray NativeCrypto_SSL_CTX_get_ciphers(JNIEnv* env,
+        jclass, jint ssl_ctx_address)
+{
+    SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
+    if (ssl_ctx == NULL) {
+        jniThrowNullPointerException(env, "SSL_CTX is null");
+        return NULL;
     }
-
-    return ssl;
+    return makeCipherList(env, ssl_ctx->cipher_list);
 }
 
-// ============================================================================
-// === OpenSSL-related helper stuff begins here. ==============================
-// ============================================================================
-
 /**
- * OpenSSL locking support. Taken from the O'Reilly book by Viega et al., but I
- * suppose there are not many other ways to do this on a Linux system (modulo
- * isomorphism).
+ * public static native void SSL_CTX_free(int ssl_ctx)
  */
-#define MUTEX_TYPE pthread_mutex_t
-#define MUTEX_SETUP(x) pthread_mutex_init(&(x), NULL)
-#define MUTEX_CLEANUP(x) pthread_mutex_destroy(&(x))
-#define MUTEX_LOCK(x) pthread_mutex_lock(&(x))
-#define MUTEX_UNLOCK(x) pthread_mutex_unlock(&(x))
-#define THREAD_ID pthread_self()
-#define THROW_EXCEPTION (-2)
-#define THROW_SOCKETTIMEOUTEXCEPTION (-3)
-
-static MUTEX_TYPE *mutex_buf = NULL;
-
-static void locking_function(int mode, int n, const char * file, int line) {
-    if (mode & CRYPTO_LOCK) {
-        MUTEX_LOCK(mutex_buf[n]);
-    } else {
-        MUTEX_UNLOCK(mutex_buf[n]);
+static void NativeCrypto_SSL_CTX_free(JNIEnv* env,
+        jclass, jint ssl_ctx_address)
+{
+    SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
+    if (ssl_ctx == NULL) {
+        jniThrowNullPointerException(env, "SSL_CTX is null");
+        return;
     }
+    SSL_CTX_free(ssl_ctx);
 }
 
-static unsigned long id_function(void) {
-    return ((unsigned long)THREAD_ID);
-}
-
-int THREAD_setup(void) {
-    int i;
+/**
+ * Gets the chars of a String object as a '\0'-terminated UTF-8 string,
+ * stored in a freshly-allocated BIO memory buffer.
+ */
+static BIO *stringToMemBuf(JNIEnv* env, jstring string) {
+    jsize byteCount = env->GetStringUTFLength(string);
+    LocalArray<1024> buf(byteCount + 1);
+    env->GetStringUTFRegion(string, 0, env->GetStringLength(string), &buf[0]);
 
-    mutex_buf = (MUTEX_TYPE *)malloc(CRYPTO_num_locks( ) * sizeof(MUTEX_TYPE));
+    BIO* result = BIO_new(BIO_s_mem());
+    BIO_puts(result, &buf[0]);
+    return result;
+}
 
-    if(!mutex_buf) {
+/**
+ * public static native int SSL_new(int ssl_ctx, String privatekey, String certificate, byte[] seed) throws IOException;
+ */
+static jint NativeCrypto_SSL_new(JNIEnv* env, jclass,
+        jint ssl_ctx_address, jstring privatekey, jstring certificates, jbyteArray seed)
+{
+    SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
+    if (ssl_ctx == NULL) {
+        jniThrowNullPointerException(env, "SSL_CTX is null");
         return 0;
     }
 
-    for (i = 0; i < CRYPTO_num_locks( ); i++) {
-        MUTEX_SETUP(mutex_buf[i]);
+    // 'seed == null' when no SecureRandom Object is set
+    // in the SSLContext.
+    if (seed != NULL) {
+        jbyte* randseed = env->GetByteArrayElements(seed, NULL);
+        RAND_seed((unsigned char*) randseed, 1024);
+        env->ReleaseByteArrayElements(seed, randseed, 0);
+    } else {
+        RAND_load_file("/dev/urandom", 1024);
     }
 
-    CRYPTO_set_id_callback(id_function);
-    CRYPTO_set_locking_callback(locking_function);
+    SSL* ssl = SSL_new(ssl_ctx);
+    if (ssl == NULL) {
+        throwIOExceptionWithSslErrors(env, 0, 0,
+                "Unable to create SSL structure");
+        return NULL;
+    }
 
-    return 1;
-}
+    /* Java code in class OpenSSLSocketImpl does the verification. Meaning of
+     * SSL_VERIFY_NONE flag in client mode: if not using an anonymous cipher
+     * (by default disabled), the server will send a certificate which will
+     * be checked. The result of the certificate verification process can be
+     * checked after the TLS/SSL handshake using the SSL_get_verify_result(3)
+     * function. The handshake will be continued regardless of the
+     * verification result.
+     */
+    SSL_set_verify(ssl, SSL_VERIFY_NONE, NULL);
 
-int THREAD_cleanup(void) {
-    int i;
+    if (privatekey != NULL) {
+        BIO* privatekeybio = stringToMemBuf(env, (jstring) privatekey);
+        EVP_PKEY* privatekeyevp =
+          PEM_read_bio_PrivateKey(privatekeybio, NULL, 0, NULL);
+        BIO_free(privatekeybio);
 
-    if (!mutex_buf) {
-      return 0;
-    }
+        if (privatekeyevp == NULL) {
+            LOGE(ERR_error_string(ERR_get_error(), NULL));
+            throwIOExceptionWithSslErrors(env, 0, 0,
+                    "Error parsing the private key");
+            SSL_free(ssl);
+            return NULL;
+        }
 
-    CRYPTO_set_id_callback(NULL);
-    CRYPTO_set_locking_callback(NULL);
+        BIO* certificatesbio = stringToMemBuf(env, (jstring) certificates);
+        X509* certificatesx509 =
+          PEM_read_bio_X509(certificatesbio, NULL, 0, NULL);
+        BIO_free(certificatesbio);
 
-    for (i = 0; i < CRYPTO_num_locks( ); i++) {
-        MUTEX_CLEANUP(mutex_buf[i]);
-    }
+        if (certificatesx509 == NULL) {
+            LOGE(ERR_error_string(ERR_get_error(), NULL));
+            throwIOExceptionWithSslErrors(env, 0, 0,
+                    "Error parsing the certificates");
+            EVP_PKEY_free(privatekeyevp);
+            SSL_free(ssl);
+            return NULL;
+        }
 
-    free(mutex_buf);
-    mutex_buf = NULL;
+        int ret = SSL_use_certificate(ssl, certificatesx509);
+        if (ret != 1) {
+            LOGE(ERR_error_string(ERR_get_error(), NULL));
+            throwIOExceptionWithSslErrors(env, ret, 0,
+                    "Error setting the certificates");
+            X509_free(certificatesx509);
+            EVP_PKEY_free(privatekeyevp);
+            SSL_free(ssl);
+            return NULL;
+        }
 
-    return 1;
-}
+        ret = SSL_use_PrivateKey(ssl, privatekeyevp);
+        if (ret != 1) {
+            LOGE(ERR_error_string(ERR_get_error(), NULL));
+            throwIOExceptionWithSslErrors(env, ret, 0,
+                    "Error setting the private key");
+            X509_free(certificatesx509);
+            EVP_PKEY_free(privatekeyevp);
+            SSL_free(ssl);
+            return NULL;
+        }
 
-int get_socket_timeout(int type, int sd) {
-    struct timeval tv;
-    socklen_t len = sizeof(tv);
-    if (getsockopt(sd, SOL_SOCKET, type, &tv, &len) < 0) {
-         LOGE("getsockopt(%d, SOL_SOCKET): %s (%d)",
-              sd,
-              strerror(errno),
-              errno);
-        return 0;         
+        ret = SSL_check_private_key(ssl);
+        if (ret != 1) {
+            throwIOExceptionWithSslErrors(env, ret, 0,
+                    "Error checking the private key");
+            X509_free(certificatesx509);
+            EVP_PKEY_free(privatekeyevp);
+            SSL_free(ssl);
+            return NULL;
+        }
     }
-    // LOGI("Current socket timeout (%d(s), %d(us))!",
-    //      (int)tv.tv_sec, (int)tv.tv_usec);
-    int timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
-    return timeout;
+    return (jint)ssl;
 }
 
-#ifdef TIMEOUT_DEBUG_SSL
+/**
+ * public static native long SSL_get_options(int ssl);
+ */
+static jlong NativeCrypto_SSL_get_options(JNIEnv* env, jclass,
+        jint ssl_address) {
+    SSL* ssl = getSslPointer(env, ssl_address, true);
+    if (ssl == NULL) {
+      return 0;
+    }
+    return SSL_get_options(ssl);
+}
 
-void print_socket_timeout(const char* name, int type, int sd) {
-    struct timeval tv;
-    int len = sizeof(tv);
-    if (getsockopt(sd, SOL_SOCKET, type, &tv, &len) < 0) {
-         LOGE("getsockopt(%d, SOL_SOCKET, %s): %s (%d)",
-              sd,
-              name,
-              strerror(errno),
-              errno);
+/**
+ * public static native long SSL_set_options(int ssl, long options);
+ */
+static jlong NativeCrypto_SSL_set_options(JNIEnv* env, jclass,
+        jint ssl_address, jlong options) {
+    SSL* ssl = getSslPointer(env, ssl_address, true);
+    if (ssl == NULL) {
+      return 0 ;
     }
-    LOGI("Current socket %s is (%d(s), %d(us))!",
-          name, (int)tv.tv_sec, (int)tv.tv_usec);
+    return SSL_set_options(ssl, options);
 }
 
-void print_timeout(const char* method, SSL* ssl) {    
-    LOGI("SSL_get_default_timeout %d in %s", SSL_get_default_timeout(ssl), method);
-    int fd = SSL_get_fd(ssl);
-    print_socket_timeout("SO_RCVTIMEO", SO_RCVTIMEO, fd);
-    print_socket_timeout("SO_SNDTIMEO", SO_SNDTIMEO, fd);
+/**
+ * Loads the ciphers suites that are enabled in the SSL
+ * and returns them in a string array.
+ */
+static jobjectArray NativeCrypto_SSL_get_ciphers(JNIEnv* env,
+        jclass, jint ssl_address)
+{
+    SSL* ssl = getSslPointer(env, ssl_address, true);
+    if (ssl == NULL) {
+      return NULL;
+    }
+    return makeCipherList(env, SSL_get_ciphers(ssl));
 }
 
-#endif
+/**
+ * Sets the ciphers suites that are enabled in the SSL
+ */
+static void NativeCrypto_SSL_set_cipher_list(JNIEnv* env, jclass,
+        jint ssl_address, jstring controlString)
+{
+    SSL* ssl = getSslPointer(env, ssl_address, true);
+    if (ssl == NULL) {
+      return;
+    }
+    const char* str = env->GetStringUTFChars(controlString, NULL);
+    int rc = SSL_set_cipher_list(ssl, str);
+    env->ReleaseStringUTFChars(controlString, str);
+    if (rc == 0) {
+        freeSslErrorState();
+        jniThrowException(env, "java/lang/IllegalArgumentException",
+                          "Illegal cipher suite strings.");
+    }
+}
 
 /**
  * Our additional application data needed for getting synchronization right.
  * This maybe warrants a bit of lengthy prose:
- * 
+ *
  * (1) We use a flag to reflect whether we consider the SSL connection alive.
  * Any read or write attempt loops will be cancelled once this flag becomes 0.
- * 
+ *
  * (2) We use an int to count the number of threads that are blocked by the
  * underlying socket. This may be at most two (one reader and one writer), since
  * the Java layer ensures that no more threads will enter the native code at the
  * same time.
- * 
+ *
  * (3) The pipe is used primarily as a means of cancelling a blocking select()
  * when we want to close the connection (aka "emergency button"). It is also
  * necessary for dealing with a possible race condition situation: There might
@@ -687,23 +926,23 @@ void print_timeout(const char* method, SSL* ssl) {
  * If one leaves the select() successfully before the other enters it, the
  * "success" event is already consumed and the second thread will be blocked,
  * possibly forever (depending on network conditions).
- *  
+ *
  * The idea for solving the problem looks like this: Whenever a thread is
  * successful in moving around data on the network, and it knows there is
  * another thread stuck in a select(), it will write a byte to the pipe, waking
  * up the other thread. A thread that returned from select(), on the other hand,
  * knows whether it's been woken up by the pipe. If so, it will consume the
  * byte, and the original state of affairs has been restored.
- * 
+ *
  * The pipe may seem like a bit of overhead, but it fits in nicely with the
  * other file descriptors of the select(), so there's only one condition to wait
  * for.
- * 
+ *
  * (4) Finally, a mutex is needed to make sure that at most one thread is in
  * either SSL_read() or SSL_write() at any given time. This is an OpenSSL
  * requirement. We use the same mutex to guard the field for counting the
  * waiting threads.
- * 
+ *
  * Note: The current implementation assumes that we don't have to deal with
  * problems induced by multiple cores or processors and their respective
  * memory caches. One possible problem is that of inconsistent views on the
@@ -712,7 +951,7 @@ void print_timeout(const char* method, SSL* ssl) {
  * currently this seems a bit like overkill.
  */
 typedef struct app_data {
-    int aliveAndKicking;
+    volatile int aliveAndKicking;
     int waitingThreads;
     int fdsEmergency[2];
     MUTEX_TYPE mutex;
@@ -720,7 +959,7 @@ typedef struct app_data {
 
 /**
  * Creates our application data and attaches it to a given SSL connection.
- * 
+ *
  * @param ssl The SSL connection to attach the data to.
  * @return 0 on success, -1 on failure.
  */
@@ -751,16 +990,16 @@ static int sslCreateAppData(SSL* ssl) {
 
 /**
  * Destroys our application data, cleaning up everything in the process.
- * 
+ *
  * @param ssl The SSL connection to take the data from.
- */ 
+ */
 static void sslDestroyAppData(SSL* ssl) {
     APP_DATA* data = (APP_DATA*) SSL_get_app_data(ssl);
 
     if (data != NULL) {
         SSL_set_app_data(ssl, NULL);
 
-        data -> aliveAndKicking = 0;
+        data->aliveAndKicking = 0;
 
         if (data->fdsEmergency[0] != -1) {
             close(data->fdsEmergency[0]);
@@ -776,72 +1015,101 @@ static void sslDestroyAppData(SSL* ssl) {
     }
 }
 
-
 /**
- * Frees the SSL_CTX struct for the given instance.
+ * public static native void SSL_free(int ssl);
  */
-static void free_ssl_ctx(JNIEnv* env, jobject object) {
-    /*
-     * Preserve and restore the exception state around this call, so
-     * that GetIntField and SetIntField will operate without complaint.
-     */
-    jthrowable exception = env->ExceptionOccurred();
-
-    if (exception != NULL) {
-        env->ExceptionClear();
-    }
-
-    SSL_CTX *ctx = (SSL_CTX *)env->GetIntField(object, field_Socket_ssl_ctx);
-
-    if (ctx != NULL) {
-        SSL_CTX_free(ctx);
-        env->SetIntField(object, field_Socket_ssl_ctx, (int) NULL);
-    }
-
-    if (exception != NULL) {
-        env->Throw(exception);
+static void NativeCrypto_SSL_free(JNIEnv* env, jclass, jint ssl_address)
+{
+    SSL* ssl = getSslPointer(env, ssl_address, true);
+    if (ssl == NULL) {
+      return;
     }
+    sslDestroyAppData(ssl);
+    SSL_free(ssl);
 }
 
-/**
- * Frees the SSL struct for the given instance.
+/*
+ * Defines the mapping from Java methods and their signatures
+ * to native functions. Order is (1) Java name, (2) signature,
+ * (3) pointer to C function.
  */
-static void free_ssl(JNIEnv* env, jobject object) {
-    /*
-     * Preserve and restore the exception state around this call, so
-     * that GetIntField and SetIntField will operate without complaint.
-     */
-    jthrowable exception = env->ExceptionOccurred();
+static JNINativeMethod sNativeCryptoMethods[] = {
+    { "clinit",              "()V",           (void*)NativeCrypto_clinit},
+    { "EVP_PKEY_new_DSA",    "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_DSA },
+    { "EVP_PKEY_new_RSA",    "([B[B[B[B[B)I", (void*)NativeCrypto_EVP_PKEY_new_RSA },
+    { "EVP_PKEY_free",       "(I)V",          (void*)NativeCrypto_EVP_PKEY_free },
+    { "EVP_new",             "()I",           (void*)NativeCrypto_EVP_new },
+    { "EVP_free",            "(I)V",          (void*)NativeCrypto_EVP_free },
+    { "EVP_DigestFinal",     "(I[BI)I",       (void*)NativeCrypto_EVP_DigestFinal },
+    { "EVP_DigestInit",      "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_DigestInit },
+    { "EVP_DigestBlockSize", "(I)I",          (void*)NativeCrypto_EVP_DigestBlockSize },
+    { "EVP_DigestSize",      "(I)I",          (void*)NativeCrypto_EVP_DigestSize },
+    { "EVP_DigestUpdate",    "(I[BII)V",      (void*)NativeCrypto_EVP_DigestUpdate },
+    { "EVP_VerifyInit",      "(ILjava/lang/String;)V", (void*)NativeCrypto_EVP_VerifyInit },
+    { "EVP_VerifyUpdate",    "(I[BII)V",      (void*)NativeCrypto_EVP_VerifyUpdate },
+    { "EVP_VerifyFinal",     "(I[BIII)I",     (void*)NativeCrypto_EVP_VerifyFinal },
+    { "SSL_CTX_new",         "()I",           (void*)NativeCrypto_SSL_CTX_new },
+    { "SSL_CTX_get_ciphers", "(I)[Ljava/lang/String;", (void*)NativeCrypto_SSL_CTX_get_ciphers},
+    { "SSL_CTX_free",        "(I)V",          (void*)NativeCrypto_SSL_CTX_free },
+    { "SSL_new",             "(ILjava/lang/String;Ljava/lang/String;[B)I", (void*)NativeCrypto_SSL_new},
+    { "SSL_get_options",     "(I)J",          (void*)NativeCrypto_SSL_get_options },
+    { "SSL_set_options",     "(IJ)J",         (void*)NativeCrypto_SSL_set_options },
+    { "SSL_get_ciphers",     "(I)[Ljava/lang/String;", (void*)NativeCrypto_SSL_get_ciphers},
+    { "SSL_set_cipher_list", "(ILjava/lang/String;)V", (void*)NativeCrypto_SSL_set_cipher_list},
+    { "SSL_free",            "(I)V",          (void*)NativeCrypto_SSL_free},
+};
 
-    if (exception != NULL) {
-        env->ExceptionClear();
-    }
+/**
+ * Module scope variables initialized during JNI registration.
+ */
+static jfieldID field_Socket_mImpl;
+static jfieldID field_Socket_mFD;
 
-    SSL *ssl = (SSL *)env->GetIntField(object, field_Socket_ssl);
+// ============================================================================
+// === OpenSSL-related helper stuff begins here. ==============================
+// ============================================================================
 
-    if (ssl != NULL) {
-        sslDestroyAppData(ssl);
-        SSL_free(ssl);
-        env->SetIntField(object, field_Socket_ssl, (int) NULL);
+int get_socket_timeout(int type, int sd) {
+    struct timeval tv;
+    socklen_t len = sizeof(tv);
+    if (getsockopt(sd, SOL_SOCKET, type, &tv, &len) < 0) {
+         LOGE("getsockopt(%d, SOL_SOCKET): %s (%d)",
+              sd,
+              strerror(errno),
+              errno);
+        return 0;
     }
+    // LOGI("Current socket timeout (%d(s), %d(us))!",
+    //      (int)tv.tv_sec, (int)tv.tv_usec);
+    int timeout = tv.tv_sec * 1000 + tv.tv_usec / 1000;
+    return timeout;
+}
 
-    if (exception != NULL) {
-        env->Throw(exception);
+#ifdef TIMEOUT_DEBUG_SSL
+
+void print_socket_timeout(const char* name, int type, int sd) {
+    struct timeval tv;
+    int len = sizeof(tv);
+    if (getsockopt(sd, SOL_SOCKET, type, &tv, &len) < 0) {
+         LOGE("getsockopt(%d, SOL_SOCKET, %s): %s (%d)",
+              sd,
+              name,
+              strerror(errno),
+              errno);
     }
+    LOGI("Current socket %s is (%d(s), %d(us))!",
+          name, (int)tv.tv_sec, (int)tv.tv_usec);
 }
 
-/**
- * Constructs the SSL struct for the given instance, replacing one
- * that was already made, if any.
- */
-static SSL* create_ssl(JNIEnv* env, jobject object, SSL_CTX*  ssl_ctx) {
-    free_ssl(env, object);
-
-    SSL *ssl = SSL_new(ssl_ctx);
-    env->SetIntField(object, field_Socket_ssl, (int) ssl);
-    return ssl;
+void print_timeout(const char* method, SSL* ssl) {
+    LOGI("SSL_get_default_timeout %d in %s", SSL_get_default_timeout(ssl), method);
+    int fd = SSL_get_fd(ssl);
+    print_socket_timeout("SO_RCVTIMEO", SO_RCVTIMEO, fd);
+    print_socket_timeout("SO_SNDTIMEO", SO_SNDTIMEO, fd);
 }
 
+#endif
+
 /**
  * Dark magic helper function that checks, for a given SSL session, whether it
  * can SSL_read() or SSL_write() without blocking. Takes into account any
@@ -851,15 +1119,15 @@ static SSL* create_ssl(JNIEnv* env, jobject object, SSL_CTX*  ssl_ctx) {
  * specifies whether we are waiting for readability or writability. It expects
  * to be passed either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE, since we
  * only need to wait in case one of these problems occurs.
- * 
+ *
  * @param type Either SSL_ERROR_WANT_READ or SSL_ERROR_WANT_WRITE
  * @param fd The file descriptor to wait for (the underlying socket)
- * @param data The application data structure with mutex info etc. 
+ * @param data The application data structure with mutex info etc.
  * @param timeout The timeout value for select call, with the special value
  *                0 meaning no timeout at all (wait indefinitely). Note: This is
  *                the Java semantics of the timeout value, not the usual
  *                select() semantics.
- * @return The result of the inner select() call, -1 on additional errors 
+ * @return The result of the inner select() call, -1 on additional errors
  */
 static int sslSelect(int type, int fd, APP_DATA *data, int timeout) {
     fd_set rfds;
@@ -888,16 +1156,16 @@ static int sslSelect(int type, int fd, APP_DATA *data, int timeout) {
     } else {
         ptv = NULL;
     }
-    
+
     // LOGD("Doing select() for SSL_ERROR_WANT_%s...", type == SSL_ERROR_WANT_READ ? "READ" : "WRITE");
     int result = select(max + 1, &rfds, &wfds, NULL, ptv);
     // LOGD("Returned from select(), result is %d", result);
-    
+
     // Lock
     if (MUTEX_LOCK(data->mutex) == -1) {
         return -1;
     }
-    
+
     // If we have been woken up by the emergency pipe, there must be a token in
     // it. Thus we can safely read it (even in a blocking way).
     if (FD_ISSET(data->fdsEmergency[0], &rfds)) {
@@ -910,7 +1178,7 @@ static int sslSelect(int type, int fd, APP_DATA *data, int timeout) {
     // Tell the world that there is now one thread less waiting for the
     // underlying network.
     data->waitingThreads--;
-    
+
     // Unlock
     MUTEX_UNLOCK(data->mutex);
     // LOGD("leave sslSelect");
@@ -921,8 +1189,8 @@ static int sslSelect(int type, int fd, APP_DATA *data, int timeout) {
  * Helper function that wakes up a thread blocked in select(), in case there is
  * one. Is being called by sslRead() and sslWrite() as well as by JNI glue
  * before closing the connection.
- * 
- * @param data The application data structure with mutex info etc. 
+ *
+ * @param data The application data structure with mutex info etc.
  */
 static void sslNotify(APP_DATA *data) {
     // Write a byte to the emergency pipe, so a concurrent select() can return.
@@ -940,7 +1208,7 @@ static void sslNotify(APP_DATA *data) {
 /**
  * Helper function which does the actual reading. The Java layer guarantees that
  * at most one thread will enter this function at any given time.
- * 
+ *
  * @param ssl non-null; the SSL context
  * @param buf non-null; buffer to read into
  * @param len length of the buffer, in bytes
@@ -953,7 +1221,7 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
         int* sslErrorCode, int timeout) {
 
     // LOGD("Entering sslRead, caller requests to read %d bytes...", len);
-    
+
     if (len == 0) {
         // Don't bother doing anything in this case.
         return 0;
@@ -961,7 +1229,7 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
 
     int fd = SSL_get_fd(ssl);
     BIO *bio = SSL_get_rbio(ssl);
-    
+
     APP_DATA* data = (APP_DATA*) SSL_get_app_data(ssl);
 
     while (data->aliveAndKicking) {
@@ -973,7 +1241,7 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
         }
 
         unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio);
-        
+
         // LOGD("Doing SSL_Read()");
         int result = SSL_read(ssl, buf, len);
         int error = SSL_ERROR_NONE;
@@ -989,13 +1257,13 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
         if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved && data->waitingThreads > 0) {
             sslNotify(data);
         }
-        
+
         // If we are blocked by the underlying socket, tell the world that
         // there will be one more waiting thread now.
         if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) {
             data->waitingThreads++;
         }
-        
+
         // Unlock
         MUTEX_UNLOCK(data->mutex);
 
@@ -1010,7 +1278,7 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
                 return -1;
             }
 
-            // Need to wait for availability of underlying layer, then retry. 
+            // Need to wait for availability of underlying layer, then retry.
             case SSL_ERROR_WANT_READ:
             case SSL_ERROR_WANT_WRITE: {
                 int selectResult = sslSelect(error, fd, data, timeout);
@@ -1021,7 +1289,7 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
                 } else if (selectResult == 0) {
                     return THROW_SOCKETTIMEOUTEXCEPTION;
                 }
-                
+
                 break;
             }
 
@@ -1033,16 +1301,16 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
                 if (result == 0) {
                     return -1;
                 }
-                
+
                 // System call has been interrupted. Simply retry.
                 if (errno == EINTR) {
                     break;
                 }
-                
+
                 // Note that for all other system call errors we fall through
-                // to the default case, which results in an Exception. 
+                // to the default case, which results in an Exception.
             }
-            
+
             // Everything else is basically an error.
             default: {
                 *sslReturnCode = result;
@@ -1051,14 +1319,14 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
             }
         }
     }
-    
+
     return -1;
 }
 
 /**
  * Helper function which does the actual writing. The Java layer guarantees that
  * at most one thread will enter this function at any given time.
- * 
+ *
  * @param ssl non-null; the SSL context
  * @param buf non-null; buffer to write
  * @param len length of the buffer, in bytes
@@ -1069,29 +1337,29 @@ static int sslRead(SSL* ssl, char* buf, jint len, int* sslReturnCode,
  */
 static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
         int* sslErrorCode) {
-  
+
     // LOGD("Entering sslWrite(), caller requests to write %d bytes...", len);
 
     if (len == 0) {
         // Don't bother doing anything in this case.
         return 0;
     }
-    
+
     int fd = SSL_get_fd(ssl);
     BIO *bio = SSL_get_wbio(ssl);
-    
+
     APP_DATA* data = (APP_DATA*) SSL_get_app_data(ssl);
-    
+
     int count = len;
-    
-    while(data->aliveAndKicking && len > 0) {
+
+    while (data->aliveAndKicking && len > 0) {
         errno = 0;
         if (MUTEX_LOCK(data->mutex) == -1) {
             return -1;
         }
-        
+
         unsigned int bytesMoved = BIO_number_read(bio) + BIO_number_written(bio);
-        
+
         // LOGD("Doing SSL_write() with %d bytes to go", len);
         int result = SSL_write(ssl, buf, len);
         int error = SSL_ERROR_NONE;
@@ -1107,15 +1375,15 @@ static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
         if (BIO_number_read(bio) + BIO_number_written(bio) != bytesMoved && data->waitingThreads > 0) {
             sslNotify(data);
         }
-        
+
         // If we are blocked by the underlying socket, tell the world that
         // there will be one more waiting thread now.
         if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) {
             data->waitingThreads++;
         }
-        
+
         MUTEX_UNLOCK(data->mutex);
-        
+
         switch (error) {
              // Sucessfully write at least one byte.
             case SSL_ERROR_NONE: {
@@ -1128,7 +1396,7 @@ static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
             case SSL_ERROR_ZERO_RETURN: {
                 return -1;
             }
-                
+
             // Need to wait for availability of underlying layer, then retry.
             // The concept of a write timeout doesn't really make sense, and
             // it's also not standard Java behavior, so we wait forever here.
@@ -1142,7 +1410,7 @@ static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
                 } else if (selectResult == 0) {
                     return THROW_SOCKETTIMEOUTEXCEPTION;
                 }
-                
+
                 break;
             }
 
@@ -1154,16 +1422,16 @@ static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
                 if (result == 0) {
                     return -1;
                 }
-                
+
                 // System call has been interrupted. Simply retry.
                 if (errno == EINTR) {
                     break;
                 }
-                
+
                 // Note that for all other system call errors we fall through
-                // to the default case, which results in an Exception. 
+                // to the default case, which results in an Exception.
             }
-            
+
             // Everything else is basically an error.
             default: {
                 *sslReturnCode = result;
@@ -1173,20 +1441,20 @@ static int sslWrite(SSL* ssl, const char* buf, jint len, int* sslReturnCode,
         }
     }
     // LOGD("Successfully wrote %d bytes", count);
-    
+
     return count;
 }
 
 /**
  * Helper function that creates an RSA public key from two buffers containing
  * the big-endian bit representation of the modulus and the public exponent.
- * 
+ *
  * @param mod The data of the modulus
  * @param modLen The length of the modulus data
  * @param exp The data of the exponent
  * @param expLen The length of the exponent data
- * 
- * @return A pointer to the new RSA structure, or NULL on error 
+ *
+ * @return A pointer to the new RSA structure, or NULL on error
  */
 static RSA* rsaCreateKey(unsigned char* mod, int modLen, unsigned char* exp, int expLen) {
     // LOGD("Entering rsaCreateKey()");
@@ -1207,7 +1475,7 @@ static RSA* rsaCreateKey(unsigned char* mod, int modLen, unsigned char* exp, int
 /**
  * Helper function that frees an RSA key. Just calls the corresponding OpenSSL
  * function.
- * 
+ *
  * @param rsa The pointer to the new RSA structure to free.
  */
 static void rsaFreeKey(RSA* rsa) {
@@ -1220,16 +1488,16 @@ static void rsaFreeKey(RSA* rsa) {
 
 /**
  * Helper function that verifies a given RSA signature for a given message.
- * 
+ *
  * @param msg The message to verify
  * @param msgLen The length of the message
  * @param sig The signature to verify
  * @param sigLen The length of the signature
  * @param algorithm The name of the hash/sign algorithm to use, e.g. "RSA-SHA1"
  * @param rsa The RSA public key to use
- * 
+ *
  * @return 1 on success, 0 on failure, -1 on error (check SSL errors then)
- * 
+ *
  */
 static int rsaVerify(unsigned char* msg, unsigned int msgLen, unsigned char* sig,
                      unsigned int sigLen, char* algorithm, RSA* rsa) {
@@ -1248,186 +1516,44 @@ static int rsaVerify(unsigned char* msg, unsigned int msgLen, unsigned char* sig
 
     EVP_MD_CTX ctx;
 
-    EVP_MD_CTX_init(&ctx);    
+    EVP_MD_CTX_init(&ctx);
     if (EVP_VerifyInit_ex(&ctx, type, NULL) == 0) {
         goto cleanup;
     }
 
     EVP_VerifyUpdate(&ctx, msg, msgLen);
-    result = EVP_VerifyFinal(&ctx, sig, sigLen, key);
-    EVP_MD_CTX_cleanup(&ctx);
-
-    cleanup:
-
-    if (key != NULL) {
-        EVP_PKEY_free(key);
-    }
-
-    return result;
-}
-
-// ============================================================================
-// === OpenSSL-related helper stuff ends here. JNI glue follows. ==============
-// ============================================================================
-
-/**
- * Initialization phase for every OpenSSL job: Loads the Error strings, the 
- * crypto algorithms and reset the OpenSSL library
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_initstatic(JNIEnv* env, jobject obj)
-{
-    SSL_load_error_strings();
-    ERR_load_crypto_strings();
-    SSL_library_init();
-    OpenSSL_add_all_algorithms();
-    THREAD_setup();
-}
-
-/**
- * Initialization phase for a socket with OpenSSL.  The server's private key
- * and X509 certificate are read and the Linux /dev/urandom file is loaded 
- * as RNG for the session keys.
- *  
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_init(JNIEnv* env, jobject object,
-        jstring privatekey, jstring certificates, jbyteArray seed)
-{   
-    SSL_CTX* ssl_ctx;
-
-    // 'seed == null' when no SecureRandom Object is set
-    // in the SSLContext.
-    if (seed != NULL) {
-        jbyte* randseed = env->GetByteArrayElements(seed, NULL);
-        RAND_seed((unsigned char*) randseed, 1024);
-        env->ReleaseByteArrayElements(seed, randseed, 0);
-    } else {
-        RAND_load_file("/dev/urandom", 1024);
-    }
-
-    ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-
-    // Note: We explicitly do not allow SSLv2 to be used. It
-    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
-
-    /* Java code in class OpenSSLSocketImpl does the verification. Meaning of 
-     * SSL_VERIFY_NONE flag in client mode: if not using an anonymous cipher
-     * (by default disabled), the server will send a certificate which will 
-     * be checked. The result of the certificate verification process can be  
-     * checked after the TLS/SSL handshake using the SSL_get_verify_result(3) 
-     * function. The handshake will be continued regardless of the 
-     * verification result.    
-     */
-    SSL_CTX_set_verify(ssl_ctx, SSL_VERIFY_NONE, NULL);
-
-    int mode = SSL_CTX_get_mode(ssl_ctx);
-    /*
-     * Turn on "partial write" mode. This means that SSL_write() will
-     * behave like Posix write() and possibly return after only
-     * writing a partial buffer. Note: The alternative, perhaps
-     * surprisingly, is not that SSL_write() always does full writes
-     * but that it will force you to retry write calls having
-     * preserved the full state of the original call. (This is icky
-     * and undesirable.)
-     */
-    mode |= SSL_MODE_ENABLE_PARTIAL_WRITE;
-#if defined(SSL_MODE_SMALL_BUFFERS) /* not all SSL versions have this */
-    mode |= SSL_MODE_SMALL_BUFFERS;  /* lazily allocate record buffers; usually saves
-                                      * 44k over the default */
-#endif
-#if defined(SSL_MODE_HANDSHAKE_CUTTHROUGH) /* not all SSL versions have this */
-    mode |= SSL_MODE_HANDSHAKE_CUTTHROUGH;  /* enable sending of client data as soon as
-                                             * ClientCCS and ClientFinished are sent */
-#endif
-
-    SSL_CTX_set_mode(ssl_ctx, mode);
-
-    if (privatekey != NULL) {
-        BIO* privatekeybio = stringToMemBuf(env, (jstring) privatekey);
-        EVP_PKEY* privatekeyevp =
-          PEM_read_bio_PrivateKey(privatekeybio, NULL, 0, NULL);
-        BIO_free(privatekeybio);
-
-        if (privatekeyevp == NULL) {
-            throwIOExceptionWithSslErrors(env, 0, 0,
-                    "Error parsing the private key");
-            SSL_CTX_free(ssl_ctx);
-            return;
-        }
-
-        BIO* certificatesbio = stringToMemBuf(env, (jstring) certificates);
-        X509* certificatesx509 =
-          PEM_read_bio_X509(certificatesbio, NULL, 0, NULL);
-        BIO_free(certificatesbio);
-
-        if (certificatesx509 == NULL) {
-            throwIOExceptionWithSslErrors(env, 0, 0,
-                    "Error parsing the certificates");
-            EVP_PKEY_free(privatekeyevp);
-            SSL_CTX_free(ssl_ctx);
-            return;
-        }
-
-        int ret = SSL_CTX_use_certificate(ssl_ctx, certificatesx509);
-        if (ret != 1) {
-            throwIOExceptionWithSslErrors(env, ret, 0,
-                    "Error setting the certificates");
-            X509_free(certificatesx509);
-            EVP_PKEY_free(privatekeyevp);
-            SSL_CTX_free(ssl_ctx);
-            return;
-        }
-
-        ret = SSL_CTX_use_PrivateKey(ssl_ctx, privatekeyevp);
-        if (ret != 1) {
-            throwIOExceptionWithSslErrors(env, ret, 0,
-                    "Error setting the private key");
-            X509_free(certificatesx509);
-            EVP_PKEY_free(privatekeyevp);
-            SSL_CTX_free(ssl_ctx);
-            return;
-        }
+    result = EVP_VerifyFinal(&ctx, sig, sigLen, key);
+    EVP_MD_CTX_cleanup(&ctx);
 
-        ret = SSL_CTX_check_private_key(ssl_ctx);
-        if (ret != 1) {
-            throwIOExceptionWithSslErrors(env, ret, 0,
-                    "Error checking the private key");
-            X509_free(certificatesx509);
-            EVP_PKEY_free(privatekeyevp);
-            SSL_CTX_free(ssl_ctx);
-            return;
-        }
+    cleanup:
+
+    if (key != NULL) {
+        EVP_PKEY_free(key);
     }
 
-    env->SetIntField(object, field_Socket_ssl_ctx, (int)ssl_ctx);
+    return result;
 }
 
+// ============================================================================
+// === OpenSSL-related helper stuff ends here. JNI glue follows. ==============
+// ============================================================================
+
 /**
  * A connection within an OpenSSL context is established. (1) A new socket is
- * constructed, (2) the TLS/SSL handshake with a server is initiated. 
+ * constructed, (2) the TLS/SSL handshake with a server is initiated.
  */
-static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(JNIEnv* env, jobject object,
-        jint ctx, jobject socketObject, jboolean client_mode, jint session)
+static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(JNIEnv* env, jclass,
+        jint ssl_address, jobject socketObject, jint timeout, jboolean client_mode, jint ssl_session_address)
 {
     // LOGD("ENTER connect");
-    int ret, fd;
-    SSL_CTX* ssl_ctx;
-    SSL* ssl;
-    SSL_SESSION* ssl_session;
-
-    ssl_ctx = (SSL_CTX*)env->GetIntField(object, field_Socket_ssl_ctx);
-
-    ssl = create_ssl(env, object, ssl_ctx);
+    SSL* ssl = getSslPointer(env, ssl_address, true);
     if (ssl == NULL) {
-        throwIOExceptionWithSslErrors(env, 0, 0,
-                "Unable to create SSL structure");
-        free_ssl_ctx(env, object);
-        return (jboolean) false;
+      return (jboolean) false;
     }
+    SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
 
     jobject socketImplObject = env->GetObjectField(socketObject, field_Socket_mImpl);
     if (socketImplObject == NULL) {
-        free_ssl(env, object);
-        free_ssl_ctx(env, object);
         throwIOExceptionStr(env,
             "couldn't get the socket impl from the socket");
         return (jboolean) false;
@@ -1435,30 +1561,25 @@ static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(
 
     jobject fdObject = env->GetObjectField(socketImplObject, field_Socket_mFD);
     if (fdObject == NULL) {
-        free_ssl(env, object);
-        free_ssl_ctx(env, object);
         throwIOExceptionStr(env,
             "couldn't get the file descriptor from the socket impl");
         return (jboolean) false;
     }
 
-    fd = jniGetFDFromFileDescriptor(env, fdObject);
+    int fd = jniGetFDFromFileDescriptor(env, fdObject);
 
-    ssl_session = (SSL_SESSION *) session;
-
-    ret = SSL_set_fd(ssl, fd);
+    int ret = SSL_set_fd(ssl, fd);
 
     if (ret != 1) {
         throwIOExceptionWithSslErrors(env, ret, 0,
                 "Error setting the file descriptor");
-        free_ssl(env, object);
-        free_ssl_ctx(env, object);
+        SSL_clear(ssl);
         return (jboolean) false;
     }
 
     if (ssl_session != NULL) {
+        // LOGD("Trying to reuse session %p", ssl_session);
         ret = SSL_set_session(ssl, ssl_session);
-
         if (ret != 1) {
             /*
              * Translate the error, and throw if it turns out to be a real
@@ -1468,8 +1589,7 @@ static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(
             if (sslErrorCode != SSL_ERROR_ZERO_RETURN) {
                 throwIOExceptionWithSslErrors(env, ret, sslErrorCode,
                         "SSL session set");
-                free_ssl(env, object);
-                free_ssl_ctx(env, object);
+                SSL_clear(ssl);
                 return (jboolean) false;
             }
         }
@@ -1482,8 +1602,7 @@ static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(
     int mode = fcntl(fd, F_GETFL);
     if (mode == -1 || fcntl(fd, F_SETFL, mode | O_NONBLOCK) == -1) {
         throwIOExceptionStr(env, "Unable to make socket non blocking");
-        free_ssl(env, object);
-        free_ssl_ctx(env, object);
+        SSL_clear(ssl);
         return (jboolean) false;
     }
 
@@ -1492,19 +1611,15 @@ static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(
      */
     if (sslCreateAppData(ssl) == -1) {
         throwIOExceptionStr(env, "Unable to create application data");
-        free_ssl(env, object);
-        free_ssl_ctx(env, object);
+        SSL_clear(ssl);
         // TODO
         return (jboolean) false;
     }
-    
+
     APP_DATA* data = (APP_DATA*) SSL_get_app_data(ssl);
-    env->SetIntField(object, field_Socket_ssl, (int)ssl);
-    
-    int timeout = (int)env->GetIntField(object, field_Socket_timeout);
-    
+
     while (data->aliveAndKicking) {
-        errno = 0;        
+        errno = 0;
         ret = SSL_connect(ssl);
         if (ret == 1) {
             break;
@@ -1525,26 +1640,24 @@ static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(
             if (error == SSL_ERROR_WANT_READ || error == SSL_ERROR_WANT_WRITE) {
                 data->waitingThreads++;
                 int selectResult = sslSelect(error, fd, data, timeout);
-                
+
                 if (selectResult == -1) {
                     throwIOExceptionWithSslErrors(env, -1, error,
                         "Connect error");
-                    free_ssl(env, object);
-                    free_ssl_ctx(env, object);
+                    SSL_clear(ssl);
                     return (jboolean) false;
                 } else if (selectResult == 0) {
                     throwSocketTimeoutException(env, "SSL handshake timed out");
+                    SSL_clear(ssl);
                     freeSslErrorState();
-                    free_ssl(env, object);
-                    free_ssl_ctx(env, object);
                     return (jboolean) false;
                 }
             } else {
                 LOGE("Unknown error %d during connect", error);
                 break;
             }
-        }        
-    } 
+        }
+    }
 
     if (ret != 1) {
         /*
@@ -1555,80 +1668,72 @@ static jboolean org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect(
         if (sslErrorCode != SSL_ERROR_ZERO_RETURN) {
             throwIOExceptionWithSslErrors(env, ret, sslErrorCode,
                     "SSL handshake failure");
-            free_ssl(env, object);
-            free_ssl_ctx(env, object);
+            SSL_clear(ssl);
             return (jboolean) false;
         }
     }
 
     if (ssl_session != NULL) {
         ret = SSL_session_reused(ssl);
-        // if (ret == 1) LOGD("A session was reused");
-        // else LOGD("A new session was negotiated");
+        // if (ret == 1) LOGD("Session %p was reused", ssl_session);
+        // else LOGD("Session %p was not reused, using new session %p", ssl_session, SSL_get_session(ssl));
         return (jboolean) ret;
     } else {
-        // LOGD("A new session was negotiated");
+        // LOGD("New session %p was negotiated", SSL_get_session(ssl));
         return (jboolean) 0;
     }
     // LOGD("LEAVE connect");
 }
 
-static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_getsslsession(JNIEnv* env, jobject object,
+static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_getsslsession(JNIEnv* env, jclass,
         jint jssl)
 {
-    return (jint) SSL_get1_session((SSL *) jssl);
+    return (jint) SSL_get1_session((SSL*) jssl);
 }
 
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept(JNIEnv* env, jobject object,
-        jobject socketObject, jint jssl_ctx, jboolean client_mode)
+static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept(JNIEnv* env, jclass,
+        jint ssl_address, jobject socketObject)
 {
-    int sd, ret;
-    BIO *bio;
-    SSL *ssl;
-    SSL_CTX *ssl_ctx;
-    jsse_ssl_app_data_t appdata;
-
-    ssl_ctx = (SSL_CTX *)jssl_ctx;
+    SSL* serverSocketSsl = reinterpret_cast<SSL*>(static_cast<uintptr_t>(ssl_address));
+    if (serverSocketSsl == NULL) {
+        throwIOExceptionWithSslErrors(env, 0, 0,
+                "Unusable SSL structure");
+        return NULL;
+    }
 
-    ssl = create_ssl(env, object, ssl_ctx);
+    SSL* ssl = SSL_dup(serverSocketSsl);
     if (ssl == NULL) {
         throwIOExceptionWithSslErrors(env, 0, 0,
                 "Unable to create SSL structure");
-        return;
+        return NULL;
     }
 
     jobject socketImplObject = env->GetObjectField(socketObject, field_Socket_mImpl);
     if (socketImplObject == NULL) {
-        free_ssl(env, object);
         throwIOExceptionStr(env, "couldn't get the socket impl from the socket");
-        return;
+        return NULL;
     }
 
     jobject fdObject = env->GetObjectField(socketImplObject, field_Socket_mFD);
     if (fdObject == NULL) {
-        free_ssl(env, object);
         throwIOExceptionStr(env, "couldn't get the file descriptor from the socket impl");
-        return;
+        return NULL;
     }
 
 
-    sd = jniGetFDFromFileDescriptor(env, fdObject);
-
-    bio = BIO_new_socket(sd, BIO_NOCLOSE);
-
-    /* The parameter client_mode must be 1 */
-    if (client_mode != 0)
-        client_mode = 1;
-    BIO_set_ssl_mode(bio, client_mode);
+    int sd = jniGetFDFromFileDescriptor(env, fdObject);
 
+    BIO* bio = BIO_new_socket(sd, BIO_NOCLOSE);
     SSL_set_bio(ssl, bio, bio);
 
     /*
-     * Fill in the appdata structure needed for the certificate callback and
-     * store this in the SSL application data slot.
+     * Fill in the stack allocated appdata structure needed for the
+     * certificate callback and store this in the SSL application data
+     * slot.
      */
+    jsse_ssl_app_data_t appdata;
     appdata.env = env;
-    appdata.object = object;
+    appdata.object = socketObject;
     SSL_set_app_data(ssl, &appdata);
 
     /*
@@ -1636,7 +1741,7 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept(JNIEn
      * Maybe we need to deal with all the special SSL error cases (WANT_*),
      * just like we do for SSL_connect(). But currently it is looking ok.
      */
-    ret = SSL_accept(ssl);
+    int ret = SSL_accept(ssl);
 
     /*
      * Clear the SSL application data slot again, so we can safely use it for
@@ -1660,8 +1765,8 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept(JNIEn
           throwIOExceptionWithSslErrors(env, ret, sslErrorCode,
               "Trouble accepting connection");
        }
-        free_ssl(env, object);
-        return;
+        SSL_clear(ssl);
+        return NULL;
     } else if (ret < 0) {
         /*
          * Translate the error and throw exception. We are sure it is an error
@@ -1670,8 +1775,8 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept(JNIEn
         int sslErrorCode = SSL_get_error(ssl, ret);
         throwIOExceptionWithSslErrors(env, ret, sslErrorCode,
                 "Trouble accepting connection");
-        free_ssl(env, object);
-        return;
+        SSL_clear(ssl);
+        return NULL;
     }
 
     /*
@@ -1682,8 +1787,8 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept(JNIEn
     int mode = fcntl(fd, F_GETFL);
     if (mode == -1 || fcntl(fd, F_SETFL, mode | O_NONBLOCK) == -1) {
         throwIOExceptionStr(env, "Unable to make socket non blocking");
-        free_ssl(env, object);
-        return;
+        SSL_clear(ssl);
+        return NULL;
     }
 
     /*
@@ -1691,126 +1796,11 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept(JNIEn
      */
     if (sslCreateAppData(ssl) == -1) {
         throwIOExceptionStr(env, "Unable to create application data");
-        free_ssl(env, object);
-        return;
-    }
-}
-
-/**
- * Loads the desired protocol for the OpenSSL client and enables it.  
- * For example SSL_OP_NO_TLSv1 means do not use TLS v. 1.
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_setenabledprotocols(JNIEnv* env, jobject object,
-        jlong protocol)
-{
-    if (protocol != 0x00000000L) {
-        if (protocol & SSL_OP_NO_SSLv3)
-            LOGD("SSL_OP_NO_SSLv3 is set");
-        if (protocol & SSL_OP_NO_TLSv1)
-            LOGD("SSL_OP_NO_TLSv1 is set");
-
-        SSL_CTX* ctx = (SSL_CTX*)env->GetIntField(object, field_Socket_ssl_ctx);
-        int options = SSL_CTX_get_options(ctx);
-        options |= protocol; // Note: SSLv2 disabled earlier.
-        SSL_CTX_set_options(ctx, options);
-    }
-}
-
-static jobjectArray makeCipherList(JNIEnv* env, SSL* ssl) {
-    STACK_OF(SSL_CIPHER)* cipher_list = SSL_get_ciphers(ssl);
-    // Count the ciphers.
-    int num = sk_SSL_CIPHER_num(cipher_list);
-    int cipherCount = 0;
-    for (int i = 0; i < num; ++i) {
-        SSL_CIPHER* cipher = sk_SSL_CIPHER_value(cipher_list, i);
-        if (strcmp(SSL_CIPHER_get_version(cipher), SSL_TXT_SSLV2) == 0) {
-            // openssl-1.0.0 includes duplicate names for SSLv2 and SSLv3 ciphers
-            continue;
-        }
-        ++cipherCount;
-    }
-
-    // Create a String[].
-    jclass stringClass = env->FindClass("java/lang/String");
-    if (stringClass == NULL) {
+        SSL_clear(ssl);
         return NULL;
     }
-    jobjectArray array = env->NewObjectArray(cipherCount, stringClass, NULL);
-    if (array == NULL) {
-        return NULL;
-    }
-
-    // Fill in the cipher names.
-    int cipherIndex = 0;
-    for (int i = 0; i < num; ++i) {
-        SSL_CIPHER* cipher = sk_SSL_CIPHER_value(cipher_list, i);
-        if (strcmp(SSL_CIPHER_get_version(cipher), SSL_TXT_SSLV2) == 0) {
-            continue;
-        }
-        env->SetObjectArrayElement(array, cipherIndex, env->NewStringUTF(cipher->name));
-        ++cipherIndex;
-    }
-    return array;
-}
-
-jobjectArray makeCipherList(JNIEnv* env, SSL_CTX* ssl_ctx) {
-    SSL* ssl = SSL_new(ssl_ctx);
-    if (ssl == NULL) {
-        return NULL;
-    }
-    jobjectArray result = makeCipherList(env, ssl);
-    SSL_free(ssl);
-    return result;
-}
-
-/**
- * Loads the ciphers suites that are supported by the OpenSSL client
- * and returns them in a string array.
- */
-static jobjectArray org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_getsupportedciphersuites(JNIEnv* env,
-        jobject object)
-{
-    SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-    if (ssl_ctx == NULL) {
-        return NULL;
-    }
-    jobjectArray result = makeCipherList(env, ssl_ctx);
-    SSL_CTX_free(ssl_ctx);
-    return result;
-}
-
-/**
- * Loads the ciphers suites that are enabled in the OpenSSL client
- * and returns them in a string array.
- */
-static jobjectArray OpenSSLSocketImpl_nativeGetEnabledCipherSuites(JNIEnv* env,
-        jclass, jint ssl_ctx_address)
-{
-    SSL_CTX* ssl_ctx =
-            reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
-    return makeCipherList(env, ssl_ctx);
-}
-
-void setEnabledCipherSuites(JNIEnv* env, jstring controlString, SSL_CTX* ssl_ctx) {
-    const char* str = env->GetStringUTFChars(controlString, NULL);
-    int rc = SSL_CTX_set_cipher_list(ssl_ctx, str);
-    env->ReleaseStringUTFChars(controlString, str);
-    if (rc == 0) {
-        freeSslErrorState();
-        jniThrowException(env, "java/lang/IllegalArgumentException",
-                          "Illegal cipher suite strings.");
-    }
-}
 
-/**
- * Sets the ciphers suites that are enabled in the OpenSSL client.
- */
-static void OpenSSLSocketImpl_nativeSetEnabledCipherSuites(JNIEnv* env, jclass,
-        jint ssl_ctx_address, jstring controlString)
-{
-    SSL_CTX* ssl_ctx =
-            reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
-    setEnabledCipherSuites(env, controlString, ssl_ctx);
+    return (jint) ssl;
 }
 
 #define SSL_aRSA                0x00000001L
@@ -1826,24 +1816,18 @@ static void OpenSSLSocketImpl_nativeSetEnabledCipherSuites(JNIEnv* env, jclass,
  * Sets  the client's crypto algorithms and authentication methods.
  */
 static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_cipherauthenticationmethod(JNIEnv* env,
-        jobject object)
+        jclass, jint ssl_address)
 {
-    SSL* ssl;
-    const SSL_CIPHER *cipher;
-    jstring ret;
-    char buf[512];
-    unsigned long alg_auth;
-    const char *au;
-
-    ssl = getSslPointer(env, object, true);
+    SSL* ssl = getSslPointer(env, ssl_address, true);
     if (ssl == NULL) {
         return NULL;
     }
 
-    cipher = SSL_get_current_cipher(ssl);
+    const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl);
 
-    alg_auth = cipher->algorithm_auth;
+    unsigned long alg_auth = cipher->algorithm_auth;
 
+    const char *au;
     switch (alg_auth) {
         case SSL_aRSA:
             au="RSA";
@@ -1874,7 +1858,7 @@ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_cipheraut
             break;
     }
 
-    ret = env->NewStringUTF(au);
+    jstring ret = env->NewStringUTF(au);
 
     return ret;
 }
@@ -1882,9 +1866,9 @@ static jstring org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_cipheraut
 /**
  * OpenSSL read function (1): only one chunk is read (returned as jint).
  */
-static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_read(JNIEnv* env, jobject object, jint timeout)
+static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_read(JNIEnv* env, jclass, jint ssl_address, jint timeout)
 {
-    SSL *ssl = getSslPointer(env, object, true);
+    SSL* ssl = getSslPointer(env, ssl_address, true);
     if (ssl == NULL) {
         return 0;
     }
@@ -1914,12 +1898,12 @@ static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_read(JNIEnv*
 }
 
 /**
- * OpenSSL read function (2): read into buffer at offset n chunks. 
+ * OpenSSL read function (2): read into buffer at offset n chunks.
  * Returns 1 (success) or value <= 0 (failure).
  */
-static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_readba(JNIEnv* env, jobject obj, jbyteArray dest, jint offset, jint len, jint timeout)
+static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_readba(JNIEnv* env, jclass, jint ssl_address, jbyteArray dest, jint offset, jint len, jint timeout)
 {
-    SSL *ssl = getSslPointer(env, obj, true);
+    SSL* ssl = getSslPointer(env, ssl_address, true);
     if (ssl == NULL) {
         return 0;
     }
@@ -1949,9 +1933,9 @@ static jint org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_readba(JNIEn
 /**
  * OpenSSL write function (1): only one chunk is written.
  */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_write(JNIEnv* env, jobject object, jint b)
+static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_write(JNIEnv* env, jclass, jint ssl_address, jint b)
 {
-    SSL *ssl = getSslPointer(env, object, true);
+    SSL* ssl = getSslPointer(env, ssl_address, true);
     if (ssl == NULL) {
         return;
     }
@@ -1971,12 +1955,12 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_write(JNIEnv
 }
 
 /**
- * OpenSSL write function (2): write into buffer at offset n chunks. 
+ * OpenSSL write function (2): write into buffer at offset n chunks.
  */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_writeba(JNIEnv* env, jobject obj,
-        jbyteArray dest, jint offset, jint len)
+static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_writeba(JNIEnv* env, jclass,
+        jint ssl_address, jbyteArray dest, jint offset, jint len)
 {
-    SSL *ssl = getSslPointer(env, obj, true);
+    SSL* ssl = getSslPointer(env, ssl_address, true);
     if (ssl == NULL) {
         return;
     }
@@ -1984,8 +1968,7 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_writeba(JNIE
     jbyte* bytes = env->GetByteArrayElements(dest, NULL);
     int returnCode = 0;
     int errorCode = 0;
-    int timeout = (int)env->GetIntField(obj, field_Socket_timeout);
-    int ret = sslWrite(ssl, (const char *) (bytes + offset), len, 
+    int ret = sslWrite(ssl, (const char *) (bytes + offset), len,
             &returnCode, &errorCode);
 
     env->ReleaseByteArrayElements(dest, bytes, 0);
@@ -2000,11 +1983,11 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_writeba(JNIE
 }
 
 /**
- * Interrupt any pending IO before closing the socket. 
+ * Interrupt any pending IO before closing the socket.
  */
 static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_interrupt(
-        JNIEnv* env, jobject object) {
-    SSL *ssl = getSslPointer(env, object, false);
+        JNIEnv* env, jclass, jint ssl_address) {
+    SSL* ssl = getSslPointer(env, ssl_address, false);
     if (ssl == NULL) {
         return;
     }
@@ -2024,11 +2007,11 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_interrupt(
 }
 
 /**
- * OpenSSL close SSL socket function. 
+ * OpenSSL close SSL socket function.
  */
 static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_close(
-        JNIEnv* env, jobject object) {
-    SSL *ssl = getSslPointer(env, object, false);
+        JNIEnv* env, jclass, jint ssl_address) {
+    SSL* ssl = getSslPointer(env, ssl_address, false);
     if (ssl == NULL) {
         return;
     }
@@ -2068,24 +2051,14 @@ static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_close(
              * Everything else is a real error condition. We should
              * let the Java layer know about this by throwing an
              * exception.
-             */ 
+             */
             int sslErrorCode = SSL_get_error(ssl, ret);
             throwIOExceptionWithSslErrors(env, ret, sslErrorCode, "SSL shutdown failed");
             break;
     }
 
+    SSL_clear(ssl);
     freeSslErrorState();
-    free_ssl(env, object);
-    free_ssl_ctx(env, object);
-}    
-
-/**
- * OpenSSL free SSL socket function. 
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_free(JNIEnv* env, jobject object)
-{
-    free_ssl(env, object);
-    free_ssl_ctx(env, object);
 }
 
 /**
@@ -2148,151 +2121,20 @@ static int org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_verifysignatu
 
 static JNINativeMethod sSocketImplMethods[] =
 {
-    {"nativeinitstatic", "()V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_initstatic},
-    {"nativeinit", "(Ljava/lang/String;Ljava/lang/String;[B)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_init},
-    {"nativeconnect", "(ILjava/net/Socket;ZI)Z", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect},
+    {"nativeconnect", "(ILjava/net/Socket;IZI)Z", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_connect},
     {"nativegetsslsession", "(I)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_getsslsession},
-    {"nativeread", "(I)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_read},
-    {"nativeread", "([BIII)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_readba},
-    {"nativewrite", "(I)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_write},
-    {"nativewrite", "([BII)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_writeba},
-    {"nativeaccept", "(Ljava/net/Socket;IZ)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept},
-    {"nativesetenabledprotocols", "(J)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_setenabledprotocols},
-    {"nativegetsupportedciphersuites", "()[Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_getsupportedciphersuites},
-    {"nativeGetEnabledCipherSuites", "(I)[Ljava/lang/String;", (void*) OpenSSLSocketImpl_nativeGetEnabledCipherSuites},
-    {"nativeSetEnabledCipherSuites", "(ILjava/lang/String;)V", (void*) OpenSSLSocketImpl_nativeSetEnabledCipherSuites},
-    {"nativecipherauthenticationmethod", "()Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_cipherauthenticationmethod},
-    {"nativeinterrupt", "()V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_interrupt},
-    {"nativeclose", "()V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_close},
-    {"nativefree", "()V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_free},
+    {"nativeread", "(II)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_read},
+    {"nativeread", "(I[BIII)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_readba},
+    {"nativewrite", "(II)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_write},
+    {"nativewrite", "(I[BII)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_writeba},
+    {"nativeaccept", "(ILjava/net/Socket;)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_accept},
+    {"nativecipherauthenticationmethod", "(I)Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_cipherauthenticationmethod},
+    {"nativeinterrupt", "(I)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_interrupt},
+    {"nativeclose", "(I)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_close},
     {"nativeverifysignature", "([B[BLjava/lang/String;[B[B)I", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLSocketImpl_verifysignature},
 };
 
 /**
- * Module scope variables initialized during JNI registration.
- */
-static jfieldID field_ServerSocket_ssl_ctx;
-
-/**
- * Initialization phase of OpenSSL: Loads the Error strings, the crypto algorithms and reset the OpenSSL library
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_initstatic(JNIEnv* env, jobject obj)
-{
-    SSL_load_error_strings();
-    ERR_load_crypto_strings();
-    SSL_library_init();
-    OpenSSL_add_all_algorithms();
-}
-
-/**
- * Initialization phase for a server socket with OpenSSL.  The server's private key and X509 certificate are read and  
- * the Linux /dev/random file is loaded as RNG for the session keys.
- *  
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_init(JNIEnv* env, jobject object,
-        jstring privatekey, jstring certificates, jbyteArray seed)
-{
-    SSL_CTX *ssl_ctx;
-    const char *privatekeychar;
-    const char *certificateschar;
-    EVP_PKEY * privatekeyevp;
-
-    BIO *privatekeybio;
-    BIO *certificatesbio;
-
-    // 'seed == null' when no SecureRandom Object is set
-    // in the SSLContext.
-    if (seed != NULL) {
-        jbyte* randseed = env->GetByteArrayElements(seed, NULL);
-        RAND_seed((unsigned char*) randseed, 1024);
-        env->ReleaseByteArrayElements(seed, randseed, 0);
-    } else {
-        RAND_load_file("/dev/urandom", 1024);
-    }
-
-    ssl_ctx = SSL_CTX_new(SSLv23_server_method());
-    SSL_CTX_set_options(ssl_ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2);
-
-    privatekeychar = env->GetStringUTFChars((jstring)privatekey, NULL);
-    privatekeybio = BIO_new_mem_buf((void*)privatekeychar, -1);
-
-    privatekeyevp = PEM_read_bio_PrivateKey(privatekeybio, NULL, 0, NULL);
-    env->ReleaseStringUTFChars(privatekey, privatekeychar);
-
-    if (privatekeyevp == NULL) {
-        LOGE(ERR_error_string(ERR_get_error(), NULL));
-        throwIOExceptionStr(env, "Error parsing the private key");
-        return;
-    }
-
-    certificateschar = env->GetStringUTFChars((jstring)certificates, NULL);
-    certificatesbio = BIO_new_mem_buf((void*)certificateschar, -1);
-
-    X509 * certificatesx509 = PEM_read_bio_X509(certificatesbio, NULL, 0, NULL);
-    env->ReleaseStringUTFChars(certificates, certificateschar);
-
-    if (certificatesx509 == NULL) {
-        LOGE(ERR_error_string(ERR_get_error(), NULL));
-        throwIOExceptionStr(env, "Error parsing the certificates");
-        return;
-    }
-
-    if (!SSL_CTX_use_certificate(ssl_ctx, certificatesx509)) {
-        LOGE(ERR_error_string(ERR_get_error(), NULL));
-        throwIOExceptionStr(env, "Error setting the certificates");
-        return;
-    }
-
-    if (!SSL_CTX_use_PrivateKey(ssl_ctx, privatekeyevp)) {
-        LOGE(ERR_error_string(ERR_get_error(), NULL));
-        throwIOExceptionStr(env, "Error setting the private key");
-        return;
-    }
-
-    if (!SSL_CTX_check_private_key(ssl_ctx)) {
-        LOGE(ERR_error_string(ERR_get_error(), NULL));
-        throwIOExceptionStr(env, "Error checking private key");
-        return;
-    }
-
-    env->SetIntField(object, field_ServerSocket_ssl_ctx, (int)ssl_ctx);
-}
-
-/**
- * Loads the desired protocol for the OpenSSL server and enables it.  
- * For example SSL_OP_NO_TLSv1 means do not use TLS v. 1.
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_setenabledprotocols(JNIEnv* env,
-        jobject object, jlong protocol)
-{
-    if (protocol != 0x00000000L) {
-        if (protocol & SSL_OP_NO_SSLv3)
-            LOGD("SSL_OP_NO_SSLv3 is set");
-        if (protocol & SSL_OP_NO_TLSv1)
-            LOGD("SSL_OP_NO_TLSv1 is set");
-
-        SSL_CTX* ctx = (SSL_CTX*)env->GetIntField(object, field_ServerSocket_ssl_ctx);
-        SSL_CTX_set_options((SSL_CTX*)ctx, SSL_OP_ALL|SSL_OP_NO_SSLv2|(long)protocol);
-    }
-}
-
-/**
- * Loads the ciphers suites that are supported by the OpenSSL server
- * and returns them in a string array.
- */
-static jobjectArray org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_getsupportedciphersuites(JNIEnv* env,
-        jobject object)
-{
-    SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_server_method());
-    if (ssl_ctx == NULL) {
-        return NULL;
-    }
-    jobjectArray result = makeCipherList(env, ssl_ctx);
-    SSL_CTX_free(ssl_ctx);
-    return result;
-}
-
-/**
  * Gives an array back containing all the X509 certificate's bytes.
  */
 static jobjectArray getcertificatebytes(JNIEnv* env,
@@ -2356,79 +2198,64 @@ static jobjectArray getcertificatebytes(JNIEnv* env,
  */
 static int verify_callback(int preverify_ok, X509_STORE_CTX *x509_store_ctx)
 {
-    SSL *ssl;
-    jsse_ssl_app_data_t *appdata;
-    jclass cls;
-
-    jobjectArray objectArray;
-
     /* Get the correct index to the SSLobject stored into X509_STORE_CTX. */
-    ssl = (SSL*)X509_STORE_CTX_get_ex_data(x509_store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
+    SSL* ssl = (SSL*)X509_STORE_CTX_get_ex_data(x509_store_ctx, SSL_get_ex_data_X509_STORE_CTX_idx());
 
-    appdata = (jsse_ssl_app_data_t*)SSL_get_app_data(ssl);
+    jsse_ssl_app_data_t* appdata = (jsse_ssl_app_data_t*)SSL_get_app_data(ssl);
 
-    cls = appdata->env->GetObjectClass(appdata->object);
+    jclass cls = appdata->env->GetObjectClass(appdata->object);
 
-    jmethodID methodID = appdata->env->GetMethodID(cls, "verify_callback", "([[B)I");
+    jmethodID methodID = appdata->env->GetMethodID(cls, "verifyCertificateChain", "([[B)Z");
 
-    objectArray = getcertificatebytes(appdata->env, x509_store_ctx->untrusted);
+    jobjectArray objectArray = getcertificatebytes(appdata->env, x509_store_ctx->untrusted);
 
-    appdata->env->CallIntMethod(appdata->object, methodID, objectArray);
+    jboolean verified = appdata->env->CallBooleanMethod(appdata->object, methodID, objectArray);
 
-    return 1;
+    return (verified) ? 1 : 0;
 }
 
 /**
  * Sets  the client's credentials and the depth of theirs verification.
  */
 static void org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_nativesetclientauth(JNIEnv* env,
-        jobject object, jint value)
-{
-    SSL_CTX *ssl_ctx = (SSL_CTX *)env->GetIntField(object, field_ServerSocket_ssl_ctx);
-    SSL_CTX_set_verify(ssl_ctx, (int)value, verify_callback);
-}
-
-/**
- * The actual SSL context is reset.
- */
-static void org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_nativefree(JNIEnv* env, jobject object)
+        jclass, jint ssl_address, jint value)
 {
-    SSL_CTX *ctx = (SSL_CTX *)env->GetIntField(object, field_ServerSocket_ssl_ctx);
-    SSL_CTX_free(ctx);
-    env->SetIntField(object, field_ServerSocket_ssl_ctx, 0);
+    SSL* ssl = getSslPointer(env, ssl_address, true);
+    if (ssl == NULL) {
+      return;
+    }
+    SSL_set_verify(ssl, (int)value, verify_callback);
 }
 
 static JNINativeMethod sServerSocketImplMethods[] =
 {
-    {"nativeinitstatic", "()V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_initstatic},
-    {"nativeinit", "(Ljava/lang/String;Ljava/lang/String;[B)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_init},
-    {"nativesetenabledprotocols", "(J)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_setenabledprotocols},
-    {"nativegetsupportedciphersuites", "()[Ljava/lang/String;", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_getsupportedciphersuites},
-    {"nativesetclientauth", "(I)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_nativesetclientauth},
-    {"nativefree", "()V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_nativefree}
+    {"nativesetclientauth", "(II)V", (void*)org_apache_harmony_xnet_provider_jsse_OpenSSLServerSocketImpl_nativesetclientauth},
 };
 
-static jfieldID field_Session_session;
-
-static SSL_SESSION* getSslSessionPointer(JNIEnv* env, jobject object) {
-    return reinterpret_cast<SSL_SESSION*>(env->GetIntField(object, field_Session_session));
+/**
+ * Our implementation of what might be considered
+ * SSL_SESSION_get_peer_cert_chain
+ */
+static STACK_OF(X509)* SSL_SESSION_get_peer_cert_chain(SSL_CTX* ssl_ctx, SSL_SESSION* ssl_session) {
+    SSL* ssl = SSL_new(ssl_ctx);
+    SSL_set_session(ssl, ssl_session);
+    STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
+    SSL_free(ssl);
+    return chain;
 }
 
 // Fills a byte[][] with the peer certificates in the chain.
 static jobjectArray OpenSSLSessionImpl_getPeerCertificatesImpl(JNIEnv* env,
-        jobject object, jint jssl)
+        jclass, jint ssl_ctx_address, jint ssl_session_address)
 {
-    SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
-    SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-    SSL* ssl = SSL_new(ssl_ctx);
-
-    SSL_set_session(ssl, ssl_session);
-
-    STACK_OF(X509)* chain = SSL_get_peer_cert_chain(ssl);
+    SSL_CTX* ssl_ctx = reinterpret_cast<SSL_CTX*>(static_cast<uintptr_t>(ssl_ctx_address));
+    if (ssl_ctx == NULL) {
+        jniThrowNullPointerException(env, "SSL_CTX is null");
+        return NULL;
+    }
+    SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
+    STACK_OF(X509)* chain = SSL_SESSION_get_peer_cert_chain(ssl_ctx, ssl_session);
     jobjectArray objectArray = getcertificatebytes(env, chain);
-
-    SSL_free(ssl);
-    SSL_CTX_free(ssl_ctx);
     return objectArray;
 }
 
@@ -2437,8 +2264,8 @@ static jobjectArray OpenSSLSessionImpl_getPeerCertificatesImpl(JNIEnv* env,
  * not certificates). Returns a byte[] containing the DER-encoded state.
  * See apache mod_ssl.
  */
-static jbyteArray OpenSSLSessionImpl_getEncoded(JNIEnv* env, jobject object) {
-    SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
+static jbyteArray OpenSSLSessionImpl_getEncoded(JNIEnv* env, jclass, jint ssl_session_address) {
+    SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
     if (ssl_session == NULL) {
         return NULL;
     }
@@ -2463,7 +2290,7 @@ static jbyteArray OpenSSLSessionImpl_getEncoded(JNIEnv* env, jobject object) {
 /**
  * Deserialize the session.
  */
-static jint OpenSSLSessionImpl_initializeNativeImpl(JNIEnv* env, jobject object, jbyteArray bytes, jint size) {
+static jint OpenSSLSessionImpl_initializeNativeImpl(JNIEnv* env, jclass, jbyteArray bytes, jint size) {
     if (bytes == NULL) {
         return 0;
     }
@@ -2479,8 +2306,8 @@ static jint OpenSSLSessionImpl_initializeNativeImpl(JNIEnv* env, jobject object,
 /**
  * Gets and returns in a byte array the ID of the actual SSL session.
  */
-static jbyteArray OpenSSLSessionImpl_getId(JNIEnv* env, jobject object) {
-    SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
+static jbyteArray OpenSSLSessionImpl_getId(JNIEnv* env, jclass, jint ssl_session_address) {
+    SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
 
     jbyteArray result = env->NewByteArray(ssl_session->session_id_length);
     if (result != NULL) {
@@ -2495,68 +2322,61 @@ static jbyteArray OpenSSLSessionImpl_getId(JNIEnv* env, jobject object) {
  * Gets and returns in a long integer the creation's time of the
  * actual SSL session.
  */
-static jlong OpenSSLSessionImpl_getCreationTime(JNIEnv* env, jobject object) {
-    SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
+static jlong OpenSSLSessionImpl_getCreationTime(JNIEnv* env, jclass, jint ssl_session_address) {
+    SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
     jlong result = SSL_SESSION_get_time(ssl_session);
     result *= 1000; // OpenSSL uses seconds, Java uses milliseconds.
     return result;
 }
 
 /**
+ * Our implementation of what might be considered
+ * SSL_SESSION_get_version, based on SSL_get_version.
+ * See get_ssl_version above.
+ */
+static const char* SSL_SESSION_get_version(SSL_SESSION* ssl_session) {
+  return get_ssl_version(ssl_session->ssl_version);
+}
+
+/**
  * Gets and returns in a string the version of the SSL protocol. If it
  * returns the string "unknown" it means that no connection is established.
  */
-static jstring OpenSSLSessionImpl_getProtocol(JNIEnv* env, jobject object) {
-    SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
-    SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-    SSL* ssl = SSL_new(ssl_ctx);
-
-    SSL_set_session(ssl, ssl_session);
-
-    const char* protocol = SSL_get_version(ssl);
+static jstring OpenSSLSessionImpl_getProtocol(JNIEnv* env, jclass, jint ssl_session_address) {
+    SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
+    const char* protocol = SSL_SESSION_get_version(ssl_session);
     jstring result = env->NewStringUTF(protocol);
-
-    SSL_free(ssl);
-    SSL_CTX_free(ssl_ctx);
     return result;
 }
 
 /**
  * Gets and returns in a string the set of ciphers the actual SSL session uses.
  */
-static jstring OpenSSLSessionImpl_getCipherSuite(JNIEnv* env, jobject object) {
-    SSL_SESSION* ssl_session = getSslSessionPointer(env, object);
-    SSL_CTX* ssl_ctx = SSL_CTX_new(SSLv23_client_method());
-    SSL* ssl = SSL_new(ssl_ctx);
-
-    SSL_set_session(ssl, ssl_session);
-
-    const SSL_CIPHER* cipher = SSL_get_current_cipher(ssl);
+static jstring OpenSSLSessionImpl_getCipherSuite(JNIEnv* env, jclass, jint ssl_session_address) {
+    SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(static_cast<uintptr_t>(ssl_session_address));
+    const SSL_CIPHER* cipher = ssl_session->cipher;
     jstring result = env->NewStringUTF(SSL_CIPHER_get_name(cipher));
-
-    SSL_free(ssl);
-    SSL_CTX_free(ssl_ctx);
     return result;
 }
 
 /**
  * Frees the SSL session.
  */
-static void OpenSSLSessionImpl_freeImpl(JNIEnv* env, jobject object, jint session) {
-    LOGD("Freeing OpenSSL session");
+static void OpenSSLSessionImpl_freeImpl(JNIEnv* env, jclass, jint session) {
     SSL_SESSION* ssl_session = reinterpret_cast<SSL_SESSION*>(session);
+    // LOGD("Freeing OpenSSL session %p", session);
     SSL_SESSION_free(ssl_session);
 }
 
 static JNINativeMethod sSessionImplMethods[] = {
     { "freeImpl", "(I)V", (void*) OpenSSLSessionImpl_freeImpl },
-    { "getCipherSuite", "()Ljava/lang/String;", (void*) OpenSSLSessionImpl_getCipherSuite },
-    { "getCreationTime", "()J", (void*) OpenSSLSessionImpl_getCreationTime },
-    { "getEncoded", "()[B", (void*) OpenSSLSessionImpl_getEncoded },
-    { "getId", "()[B", (void*) OpenSSLSessionImpl_getId },
-    { "getPeerCertificatesImpl", "()[[B", (void*) OpenSSLSessionImpl_getPeerCertificatesImpl },
-    { "getProtocol", "()Ljava/lang/String;", (void*) OpenSSLSessionImpl_getProtocol },
-    { "initializeNativeImpl", "([BI)I", (void*) OpenSSLSessionImpl_initializeNativeImpl }
+    { "getCipherSuite", "(I)Ljava/lang/String;", (void*) OpenSSLSessionImpl_getCipherSuite },
+    { "getCreationTime", "(I)J", (void*) OpenSSLSessionImpl_getCreationTime },
+    { "getEncoded", "(I)[B", (void*) OpenSSLSessionImpl_getEncoded },
+    { "getId", "(I)[B", (void*) OpenSSLSessionImpl_getId },
+    { "getPeerCertificatesImpl", "(II)[[B", (void*) OpenSSLSessionImpl_getPeerCertificatesImpl },
+    { "getProtocol", "(I)Ljava/lang/String;", (void*) OpenSSLSessionImpl_getProtocol },
+    { "initializeNativeImpl", "([BI)I", (void*) OpenSSLSessionImpl_initializeNativeImpl },
 };
 
 typedef struct {
@@ -2571,15 +2391,7 @@ static JNINativeClass sClasses[] = {
     { "org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl", sServerSocketImplMethods, NELEM(sServerSocketImplMethods) },
     { "org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl", sSessionImplMethods, NELEM(sSessionImplMethods) },
 };
-
-/*
- * Peforms the actual registration of the native methods.
- * Also looks up the fields that belong to the class (if
- * any) and stores the field IDs. Simply remove what you
- * don't need.
- */
-extern "C" int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env) {
-
+int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEnv* env) {
     // Register org.apache.harmony.xnet.provider.jsse.* methods
     for (int i = 0; i < NELEM(sClasses); i++) {
         int result = jniRegisterNativeMethods(env,
@@ -2591,18 +2403,6 @@ extern "C" int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEn
         }
     }
 
-    // java.io.FileDescriptor
-    jclass fileDescriptor = env->FindClass("java/io/FileDescriptor");
-    if (fileDescriptor == NULL) {
-        LOGE("Can't find java/io/FileDescriptor");
-        return -1;
-    }
-    field_FileDescriptor_descriptor = env->GetFieldID(fileDescriptor, "descriptor", "I");
-    if (field_FileDescriptor_descriptor == NULL) {
-        LOGE("Can't find FileDescriptor.descriptor");
-        return -1;
-    }
-
     // java.net.Socket
     jclass socket = env->FindClass("java/net/Socket");
     if (socket == NULL) {
@@ -2627,58 +2427,5 @@ extern "C" int register_org_apache_harmony_xnet_provider_jsse_NativeCrypto(JNIEn
         return -1;
     }
 
-    // org.apache.harmony.xnet.provider.jsse.OpenSSLSocketImpl
-    jclass socketImpl = env->FindClass("org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl");
-    if (socketImpl == NULL) {
-        LOGE("Can't find org/apache/harmony/xnet/provider/jsse/OpenSSLSocketImpl");
-        return -1;
-    }
-    // Note: do these after the registration of native methods, because 
-    // there is a static method "initstatic" that's called when the
-    // OpenSSLSocketImpl class is first loaded, and that required
-    // a native method to be associated with it.
-    field_Socket_ssl_ctx = env->GetFieldID(socketImpl, "ssl_ctx", "I");
-    if (field_Socket_ssl_ctx == NULL) {
-      LOGE("Can't find OpenSSLSocketImpl.ssl_ctx");
-      return -1;
-    }
-    field_Socket_ssl = env->GetFieldID(socketImpl, "ssl", "I");
-    if (field_Socket_ssl == NULL) {
-      LOGE("Can't find OpenSSLSocketImpl.ssl");
-      return -1;
-    }
-    field_Socket_timeout = env->GetFieldID(socketImpl, "timeout", "I");
-    if (field_Socket_timeout == NULL) {
-      LOGE("Can't find OpenSSLSocketImpl.timeout");
-      return -1;
-    }
-
-    // org.apache.harmony.xnet.provider.jsse.OpenSSLServerSocketImpl
-    jclass serverSocketImpl = env->FindClass("org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl");
-    if (serverSocketImpl == NULL) {
-        LOGE("Can't find org/apache/harmony/xnet/provider/jsse/OpenSSLServerSocketImpl");
-        return -1;
-    }
-    // Note: do these after the registration of native methods, because
-    // there is a static method "initstatic" that's called when the
-    // OpenSSLServerSocketImpl class is first loaded, and that required
-    // a native method to be associated with it.
-    field_ServerSocket_ssl_ctx = env->GetFieldID(serverSocketImpl, "ssl_ctx", "I");
-    if (field_ServerSocket_ssl_ctx == NULL) {
-      LOGE("Can't find OpenSSLServerSocketImpl.ssl_ctx");
-      return -1;
-    }
-
-    // org.apache.harmony.xnet.provider.jsse.OpenSSLSessionImpl
-    jclass sessionImpl = env->FindClass("org/apache/harmony/xnet/provider/jsse/OpenSSLSessionImpl");
-    if (sessionImpl == NULL) {
-        return -1;
-    }
-    field_Session_session = env->GetFieldID(sessionImpl, "session", "I");
-    if (field_Session_session == NULL) {
-      LOGE("Can't find OpenSSLSessionImpl.session");
-      return -1;
-    }
-
     return 0;
 }