Skip to content

Commit 6521c21

Browse files
committed
JNI/JSSE: remove extraneous array copy in WolfSSLInputStream/OutputStream when array offset is provided
1 parent 1d91773 commit 6521c21

4 files changed

Lines changed: 119 additions & 46 deletions

File tree

native/com_wolfssl_WolfSSLSession.c

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -753,10 +753,10 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
753753
}
754754

755755
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
756-
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray raw, jint length,
757-
jint timeout)
756+
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray raw, jint offset,
757+
jint length, jint timeout)
758758
{
759-
byte* data;
759+
byte* data = NULL;
760760
int ret = SSL_FAILURE, err, sockfd;
761761
wolfSSL_Mutex* jniSessLock = NULL;
762762
SSLAppData* appData = NULL;
@@ -767,7 +767,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
767767
return BAD_FUNC_ARG;
768768
}
769769

770-
if (length >= 0) {
770+
if ((offset >= 0) && (length >= 0)) {
771771
data = (byte*)(*jenv)->GetByteArrayElements(jenv, raw, NULL);
772772
if ((*jenv)->ExceptionOccurred(jenv)) {
773773
(*jenv)->ExceptionDescribe(jenv);
@@ -798,7 +798,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
798798
break;
799799
}
800800

801-
ret = wolfSSL_write(ssl, data, length);
801+
ret = wolfSSL_write(ssl, data + offset, length);
802802
err = wolfSSL_get_error(ssl, ret);
803803

804804
/* unlock mutex around session I/O after write attempt */
@@ -841,10 +841,11 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
841841
}
842842
}
843843

844-
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read(JNIEnv* jenv,
845-
jobject jcl, jlong sslPtr, jbyteArray raw, jint length, int timeout)
844+
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read
845+
(JNIEnv* jenv, jobject jcl, jlong sslPtr, jbyteArray raw, jint offset,
846+
jint length, jint timeout)
846847
{
847-
byte* data;
848+
byte* data = NULL;
848849
int size = 0, ret, err, sockfd;
849850
wolfSSL_Mutex* jniSessLock = NULL;
850851
SSLAppData* appData = NULL;
@@ -855,7 +856,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read(JNIEnv* jenv,
855856
return BAD_FUNC_ARG;
856857
}
857858

858-
if (length >= 0) {
859+
if ((offset >= 0) && (length >= 0)) {
859860
data = (byte*)(*jenv)->GetByteArrayElements(jenv, raw, NULL);
860861
if ((*jenv)->ExceptionOccurred(jenv)) {
861862
(*jenv)->ExceptionDescribe(jenv);
@@ -885,7 +886,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read(JNIEnv* jenv,
885886
break;
886887
}
887888

888-
size = wolfSSL_read(ssl, data, length);
889+
size = wolfSSL_read(ssl, data + offset, length);
889890
err = wolfSSL_get_error(ssl, size);
890891

891892
/* unlock mutex around session I/O after read attempt */

native/com_wolfssl_WolfSSLSession.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/java/com/wolfssl/WolfSSLSession.java

Lines changed: 98 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -252,8 +252,10 @@ private synchronized void confirmObjectIsActive()
252252
private native int getUsingNonblock(long ssl);
253253
private native int getFd(long ssl);
254254
private native int connect(long ssl, int timeout);
255-
private native int write(long ssl, byte[] data, int length, int timeout);
256-
private native int read(long ssl, byte[] data, int sz, int timeout);
255+
private native int write(long ssl, byte[] data, int offset, int length,
256+
int timeout);
257+
private native int read(long ssl, byte[] data, int offset, int sz,
258+
int timeout);
257259
private native int accept(long ssl, int timeout);
258260
private native void freeSSL(long ssl);
259261
private native int shutdownSSL(long ssl, int timeout);
@@ -728,7 +730,7 @@ public int write(byte[] data, int length)
728730
* is locked here, since we call select() inside native JNI we
729731
* could timeout waiting for corresponding read() operation to
730732
* occur if needed */
731-
ret = write(getSessionPtr(), data, length, 0);
733+
ret = write(getSessionPtr(), data, 0, length, 0);
732734

733735
if (ret == WOLFJNI_SELECT_FAIL) {
734736
throw new SocketException("Socket select() failed, errno = " +
@@ -778,14 +780,58 @@ public int write(byte[] data, int length, int timeout)
778780

779781
int ret;
780782

783+
return write(data, 0, length, timeout);
784+
}
785+
786+
/**
787+
* Write bytes from a byte array to the SSL connection, using socket
788+
* timeout value in milliseconds.
789+
* If necessary, <code>write()</code> will negotiate an SSL/TLS session
790+
* if the handshake has not already been performed yet by <code>connect
791+
* </code> or <code>accept</code>.
792+
* <p>
793+
* <code>write()</code> works with both blocking and non-blocking I/O.
794+
* When the underlying I/O is non-blocking, <code>write()</code> will
795+
* return when the underlying I/O could not satisfy the needs of <code>
796+
* write()</code> to continue. In this case, a call to <code>getError
797+
* </code> will yield either <b>SSL_ERROR_WANT_READ</b> or
798+
* <b>SSL_ERROR_WANT_WRITE</b>. The calling process must then repeat the
799+
* call to <code>write()</code> when the underlying I/O is ready.
800+
* <p>
801+
* If the underlying I/O is blocking, <code>write()</code> will only
802+
* return once the buffer <b>data</b> of size <b>length</b> has been
803+
* completely written or an error occurred.
804+
*
805+
* @param data data buffer which will be sent to peer
806+
* @param offset offset into data buffer to start writing from
807+
* @param length size, in bytes, of data to send to the peer
808+
* @param timeout read timeout, milliseconds.
809+
* @return the number of bytes written upon success. <code>0
810+
* </code>will be returned upon failure. <code>
811+
* SSL_FATAL_ERROR</code>upon failure when either an
812+
* error occurred or, when using non-blocking sockets,
813+
* the <b>SSL_ERROR_WANT_READ</b> or
814+
* <b>SSL_ERROR_WANT_WRITE</b> error was received and the
815+
* application needs to call <code>write()</code> again.
816+
* <code>BAD_FUNC_ARC</code> when bad arguments are used.
817+
* Use <code>getError</code> to get a specific error code.
818+
* @throws IllegalStateException WolfSSLContext has been freed
819+
* @throws SocketTimeoutException if socket timeout occurs
820+
* @throws SocketException Native socket select() failed
821+
*/
822+
public int write(byte[] data, int offset, int length, int timeout)
823+
throws IllegalStateException, SocketTimeoutException, SocketException {
824+
825+
int ret;
826+
781827
confirmObjectIsActive();
782828

783829
/* not synchronizing on sslLock here since JNI write() locks
784830
* session mutex around native wolfSSL_write() call. If sslLock
785831
* is locked here, since we call select() inside native JNI we
786832
* could timeout waiting for corresponding read() operation to
787833
* occur if needed */
788-
ret = write(getSessionPtr(), data, length, timeout);
834+
ret = write(getSessionPtr(), data, offset, length, timeout);
789835

790836
if (ret == WOLFJNI_TIMEOUT) {
791837
throw new SocketTimeoutException("Socket write timeout");
@@ -845,7 +891,7 @@ public int read(byte[] data, int sz)
845891
* is locked here, since we call select() inside native JNI we
846892
* could timeout waiting for corresponding write() operation to
847893
* occur if needed */
848-
ret = read(getSessionPtr(), data, sz, 0);
894+
ret = read(getSessionPtr(), data, 0, sz, 0);
849895

850896
if (ret == WOLFJNI_SELECT_FAIL) {
851897
throw new SocketException("Socket select() failed, errno = " +
@@ -897,14 +943,60 @@ public int read(byte[] data, int sz, int timeout)
897943

898944
int ret;
899945

946+
return read(data, 0, sz, timeout);
947+
}
948+
949+
/**
950+
* Reads bytes from the SSL session and returns the read bytes as a byte
951+
* array, using socket timeout value in milliseconds.
952+
* The bytes read are removed from the internal receive buffer.
953+
* <p>
954+
* If necessary, <code>read()</code> will negotiate an SSL/TLS session
955+
* if the handshake has not already been performed yet by <code>connect()
956+
* </code> or <code>accept()</code>.
957+
* <p>
958+
* The SSL/TLS protocol uses SSL records which have a maximum size of
959+
* 16kB. As such, wolfSSL needs to read an entire SSL record internally
960+
* before it is able to process and decrypt the record. Because of this,
961+
* a call to <code>read()</code> will only be able to return the
962+
* maximum buffer size which has been decrypted at the time of calling.
963+
* There may be additional not-yet-decrypted data waiting in the internal
964+
* wolfSSL receive buffer which will be retrieved and decrypted with the
965+
* next call to <code>read()</code>.
966+
*
967+
* @param data buffer where the data read from the SSL connection
968+
* will be placed.
969+
* @param offset offset into data buffer for data to be placed.
970+
* @param sz number of bytes to read into <b><code>data</code></b>
971+
* @param timeout read timeout, milliseconds.
972+
* @return the number of bytes read upon success. <code>SSL_FAILURE
973+
* </code> will be returned upon failure which may be caused
974+
* by either a clean (close notify alert) shutdown or just
975+
* that the peer closed the connection. <code>
976+
* SSL_FATAL_ERROR</code> upon failure when either an error
977+
* occurred or, when using non-blocking sockets, the
978+
* <b>SSL_ERROR_WANT_READ</b> or <b>SSL_ERROR_WANT_WRITE</b>
979+
* error was received and the application needs to call
980+
* <code>read()</code> again. Use <code>getError</code> to
981+
* get a specific error code.
982+
* <code>BAD_FUNC_ARC</code> when bad arguments are used.
983+
* @throws IllegalStateException WolfSSLContext has been freed
984+
* @throws SocketTimeoutException if socket timeout occurs
985+
* @throws SocketException Native socket select() failed
986+
*/
987+
public int read(byte[] data, int offset, int sz, int timeout)
988+
throws IllegalStateException, SocketTimeoutException, SocketException {
989+
990+
int ret;
991+
900992
confirmObjectIsActive();
901993

902994
/* not synchronizing on sslLock here since JNI read() locks
903995
* session mutex around native wolfSSL_read() call. If sslLock
904996
* is locked here, since we call select() inside native JNI we
905997
* could timeout waiting for corresponding write() operation to
906998
* occur if needed */
907-
ret = read(getSessionPtr(), data, sz, timeout);
999+
ret = read(getSessionPtr(), data, offset, sz, timeout);
9081000

9091001
if (ret == WOLFJNI_TIMEOUT) {
9101002
throw new SocketTimeoutException("Socket read timeout");

src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -2375,7 +2375,6 @@ public synchronized int read(byte[] b, int off, int len)
23752375
IOException {
23762376

23772377
int ret = 0;
2378-
byte[] data = null;
23792378

23802379
if (b == null) {
23812380
throw new NullPointerException("Input array is null");
@@ -2421,24 +2420,18 @@ public synchronized int read(byte[] b, int off, int len)
24212420
"Array index out of bounds");
24222421
}
24232422

2424-
if (off != 0) {
2425-
/* create new tmp buffer to read data into */
2426-
data = new byte[len];
2427-
} else {
2428-
data = b;
2429-
}
2430-
24312423
try {
24322424
int err;
24332425

24342426
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
24352427
"ssl.read() socket timeout = " + socket.getSoTimeout());
24362428

2437-
ret = ssl.read(data, len, socket.getSoTimeout());
2429+
ret = ssl.read(b, off, len, socket.getSoTimeout());
24382430
err = ssl.getError(ret);
24392431

24402432
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
2441-
"ssl.read() ret = " + ret + ", err = " + err);
2433+
"ssl.read(off: " + off + ", len: " + len + ") ret = " +
2434+
ret + ", err = " + err);
24422435

24432436
/* check for end of stream */
24442437
if ((err == WolfSSL.SSL_ERROR_ZERO_RETURN) ||
@@ -2468,11 +2461,6 @@ public synchronized int read(byte[] b, int off, int len)
24682461
throw new IOException(e);
24692462
}
24702463

2471-
if (off != 0) {
2472-
/* copy data into original array at offset */
2473-
System.arraycopy(data, 0, b, off, ret);
2474-
}
2475-
24762464
/* return number of bytes read */
24772465
return ret;
24782466
}
@@ -2517,7 +2505,6 @@ public synchronized void write(byte[] b, int off, int len)
25172505
throws IOException {
25182506

25192507
int ret;
2520-
byte[] data = null;
25212508

25222509
if (b == null) {
25232510
throw new NullPointerException("Input array is null");
@@ -2553,25 +2540,19 @@ public synchronized void write(byte[] b, int off, int len)
25532540
"Array index out of bounds");
25542541
}
25552542

2556-
if (off != 0) {
2557-
data = new byte[len];
2558-
System.arraycopy(b, off, data, 0, len);
2559-
} else {
2560-
data = b;
2561-
}
2562-
25632543
try {
25642544
int err;
25652545

25662546
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
25672547
"ssl.write() socket timeout = " +
25682548
socket.getSoTimeout());
25692549

2570-
ret = ssl.write(data, len, socket.getSoTimeout());
2550+
ret = ssl.write(b, off, len, socket.getSoTimeout());
25712551
err = ssl.getError(ret);
25722552

25732553
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
2574-
"ssl.write returned ret = " + ret + ", err = " + err);
2554+
"ssl.write(off: " + off + ", len: " + len +
2555+
") returned ret = " + ret + ", err = " + err);
25752556

25762557
/* check for end of stream */
25772558
if (err == WolfSSL.SSL_ERROR_ZERO_RETURN) {
@@ -2602,6 +2583,5 @@ public synchronized void write(byte[] b, int off, int len)
26022583
}
26032584
}
26042585
} /* end WolfSSLOutputStream inner class */
2605-
26062586
}
26072587

0 commit comments

Comments
 (0)