| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| #include "sslSocket.h" |
| #include <stdio.h> |
| #include "jni.h" |
| #include "hysock.h" |
| #include "openssl/bio.h" |
| #include "openssl/ssl.h" |
| #include "openssl/err.h" |
| #include "errno.h" |
| |
| jlong getFD(jlong fd) { |
| hysocket_t hysocketP = jlong2addr(hysocket_struct, fd); |
| |
| #if defined(WIN32) || defined(WIN64) |
| if (hysocketP->flags & SOCKET_IPV4_OPEN_MASK) { |
| return (jlong)(hysocketP->ipv4); |
| } else if (hysocketP->flags & SOCKET_IPV6_OPEN_MASK) { |
| return (jlong)(hysocketP->ipv6); |
| } else { |
| return 0; |
| } |
| #else |
| return (jlong)(hysocketP->sock); |
| #endif |
| } |
| |
| JNIEXPORT jlong JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_initImpl |
| (JNIEnv *env, jclass clazz, jlong context) { |
| return addr2jlong(SSL_new(jlong2addr(SSL_CTX, context))); |
| } |
| |
| JNIEXPORT void JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_sslAcceptImpl |
| (JNIEnv *env, jclass clazz, jlong jssl, jlong fd) { |
| jlong socket = getFD(fd); |
| SSL *ssl = jlong2addr(SSL, jssl); |
| BIO *bio; |
| int ret; |
| |
| bio = BIO_new_socket((int)socket, BIO_NOCLOSE); |
| SSL_set_bio(ssl, bio, bio); |
| |
| SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); |
| |
| // Put our SSL into accept state |
| SSL_set_accept_state(ssl); |
| |
| // Start the server handshake |
| ret = SSL_do_handshake(ssl); |
| if (ret<=0) { |
| jclass exception = (*env)->FindClass(env, "javax/net/ssl/SSLHandshakeException"); |
| (*env)->ThrowNew(env, exception, ERR_reason_error_string(ERR_get_error())); |
| } |
| } |
| |
| JNIEXPORT void JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_sslConnectImpl |
| (JNIEnv *env, jclass clazz, jlong jssl, jlong fd) { |
| jlong socket = getFD(fd); |
| SSL *ssl = jlong2addr(SSL, jssl); |
| BIO *bio; |
| int ret; |
| |
| bio = BIO_new_socket((int)socket, BIO_NOCLOSE); |
| SSL_set_bio(ssl, bio, bio); |
| |
| SSL_set_mode(ssl, SSL_MODE_AUTO_RETRY); |
| |
| // Put our SSL into connect state |
| SSL_set_connect_state(ssl); |
| |
| // Start the client handshake |
| ret = SSL_do_handshake(ssl); |
| if (ret<=0) { |
| jclass exception = (*env)->FindClass(env, "javax/net/ssl/SSLHandshakeException"); |
| (*env)->ThrowNew(env, exception, ERR_reason_error_string(ERR_get_error())); |
| } |
| } |
| |
| JNIEXPORT void JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_writeAppDataImpl |
| (JNIEnv *env, jclass clazz, jlong jssl, jbyteArray data, jint offset, jint len) { |
| SSL *ssl = jlong2addr(SSL, jssl); |
| int ret; |
| |
| jbyte *buffer = (jbyte*) malloc(len * sizeof(jbyte*)); |
| (*env)->GetByteArrayRegion(env, data, offset, len, buffer); |
| |
| ret = SSL_write(ssl, (const void *)buffer, (int)len); |
| // Check len bytes were written to the socket and loop if not |
| if (ret == -1) { |
| // The socket has been closed |
| jclass exception = (*env)->FindClass(env, "java/net/SocketException"); |
| (*env)->ThrowNew(env, exception, "Connection was reset"); |
| } |
| |
| free(buffer); |
| } |
| |
| JNIEXPORT jint JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_readAppDataImpl |
| (JNIEnv *env, jclass clazz, jlong jssl, jbyteArray data, jint offset, jint len) { |
| SSL *ssl = jlong2addr(SSL, jssl); |
| int ret; |
| |
| jbyte *buffer = (jbyte*) malloc(len * sizeof(jbyte*)); |
| |
| ret = SSL_read(ssl, (void *)buffer, (int)len); |
| if (ret == -1) { |
| // The socket has been closed |
| jclass exception = (*env)->FindClass(env, "java/net/SocketException"); |
| (*env)->ThrowNew(env, exception, "Connection was reset"); |
| return -1; |
| } |
| |
| (*env)->SetByteArrayRegion(env, data, offset, ret, buffer); |
| free(buffer); |
| return ret; |
| } |
| |
| JNIEXPORT void JNICALL Java_org_apache_harmony_xnet_provider_jsse_SSLSocketImpl_closeImpl |
| (JNIEnv *env, jclass clazz, jlong jssl) { |
| SSL *ssl = jlong2addr(SSL, jssl); |
| |
| // The SSLSocket is being closed, so shutdown and free our SSL |
| SSL_shutdown(ssl); |
| SSL_free(ssl); |
| } |
| |