@@ -1002,16 +1002,104 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
10021002 }
10031003}
10041004
1005- JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read
1006- (JNIEnv * jenv , jobject jcl , jlong sslPtr , jbyteArray raw , jint offset ,
1007- jint length , jint timeout )
1005+ /**
1006+ * Read len bytes from wolfSSL_read() back into provided output buffer.
1007+ *
1008+ * Internal function called by WolfSSLSession.read() calls.
1009+ *
1010+ * If wolfSSL_get_fd(ssl) returns a socket descriptor, try to wait for
1011+ * data with select()/poll() up to provided timeout.
1012+ *
1013+ * Returns number of bytes read on success, or negative on error.
1014+ */
1015+ static int SSLReadNonblockingWithSelectPoll (WOLFSSL * ssl , byte * out ,
1016+ int length , int timeout )
10081017{
1009- byte * data = NULL ;
1010- int size = 0 , ret , err , sockfd ;
1018+ int size , ret , err , sockfd ;
10111019 int pollRx = 0 ;
10121020 int pollTx = 0 ;
10131021 wolfSSL_Mutex * jniSessLock = NULL ;
10141022 SSLAppData * appData = NULL ;
1023+
1024+ if (ssl == NULL || out == NULL ) {
1025+ return BAD_FUNC_ARG ;
1026+ }
1027+
1028+ /* get session mutex from SSL app data */
1029+ appData = (SSLAppData * )wolfSSL_get_app_data (ssl );
1030+ if (appData == NULL ) {
1031+ return WOLFSSL_FAILURE ;
1032+ }
1033+
1034+ jniSessLock = appData -> jniSessLock ;
1035+ if (jniSessLock == NULL ) {
1036+ return WOLFSSL_FAILURE ;
1037+ }
1038+
1039+ do {
1040+ /* lock mutex around session I/O before read attempt */
1041+ if (wc_LockMutex (jniSessLock ) != 0 ) {
1042+ size = WOLFSSL_FAILURE ;
1043+ break ;
1044+ }
1045+
1046+ size = wolfSSL_read (ssl , out , length );
1047+ err = wolfSSL_get_error (ssl , size );
1048+
1049+ /* unlock mutex around session I/O after read attempt */
1050+ if (wc_UnLockMutex (jniSessLock ) != 0 ) {
1051+ size = WOLFSSL_FAILURE ;
1052+ break ;
1053+ }
1054+
1055+ if (size < 0 &&
1056+ ((err == SSL_ERROR_WANT_READ ) || (err == SSL_ERROR_WANT_WRITE ))) {
1057+
1058+ sockfd = wolfSSL_get_fd (ssl );
1059+ if (sockfd == -1 ) {
1060+ /* For I/O that does not use sockets, sockfd may be -1,
1061+ * skip try to call select() */
1062+ break ;
1063+ }
1064+
1065+ if (err == SSL_ERROR_WANT_READ ) {
1066+ pollRx = 1 ;
1067+ }
1068+ else if (err == SSL_ERROR_WANT_WRITE ) {
1069+ pollTx = 1 ;
1070+ }
1071+
1072+ #if defined(WOLFJNI_USE_IO_SELECT ) || defined(USE_WINDOWS_API )
1073+ ret = socketSelect (sockfd , timeout , pollRx );
1074+ #else
1075+ ret = socketPoll (sockfd , timeout , pollRx , pollTx );
1076+ #endif
1077+ if ((ret == WOLFJNI_IO_EVENT_RECV_READY ) ||
1078+ (ret == WOLFJNI_IO_EVENT_SEND_READY )) {
1079+ /* loop around and try wolfSSL_read() again */
1080+ continue ;
1081+ } else {
1082+ /* Java will throw SocketTimeoutException or
1083+ * SocketException if ret equals
1084+ * WOLFJNI_IO_EVENT_TIMEOUT, WOLFJNI_IO_EVENT_FD_CLOSED
1085+ * WOLFJNI_IO_EVENT_ERROR, WOLFJNI_IO_EVENT_POLLHUP or
1086+ * WOLFJNI_IO_EVENT_FAIL */
1087+ size = ret ;
1088+ break ;
1089+ }
1090+ }
1091+
1092+ } while (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ );
1093+
1094+ return size ;
1095+ }
1096+
1097+ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__J_3BIII
1098+ (JNIEnv * jenv , jobject jcl , jlong sslPtr , jbyteArray raw , jint offset ,
1099+ jint length , jint timeout )
1100+ {
1101+ int size = 0 ;
1102+ byte * data = NULL ;
10151103 WOLFSSL * ssl = (WOLFSSL * )(uintptr_t )sslPtr ;
10161104 (void )jcl ;
10171105
@@ -1027,79 +1115,178 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read
10271115 return SSL_FAILURE ;
10281116 }
10291117
1030- /* get session mutex from SSL app data */
1031- appData = (SSLAppData * )wolfSSL_get_app_data (ssl );
1032- if (appData == NULL ) {
1118+ size = SSLReadNonblockingWithSelectPoll (ssl , data + offset ,
1119+ (int )length , (int )timeout );
1120+
1121+ if (size < 0 ) {
10331122 (* jenv )-> ReleaseByteArrayElements (jenv , raw , (jbyte * )data ,
1034- JNI_ABORT );
1035- return WOLFSSL_FAILURE ;
1123+ JNI_ABORT );
10361124 }
1125+ else {
1126+ /* JNI_COMMIT commits the data but does not free the local array
1127+ * 0 is used here to both commit and free */
1128+ (* jenv )-> ReleaseByteArrayElements (jenv , raw , (jbyte * )data , 0 );
1129+ }
1130+ }
10371131
1038- jniSessLock = appData -> jniSessLock ;
1039- if (jniSessLock == NULL ) {
1040- (* jenv )-> ReleaseByteArrayElements (jenv , raw , (jbyte * )data ,
1041- JNI_ABORT );
1042- return WOLFSSL_FAILURE ;
1132+ return size ;
1133+ }
1134+
1135+ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__JLjava_nio_ByteBuffer_2II
1136+ (JNIEnv * jenv , jobject jcl , jlong sslPtr , jobject buf , jint length , jint timeout )
1137+ {
1138+ int size = 0 ;
1139+ int maxOutputSz ;
1140+ int outSz = length ;
1141+ byte * data = NULL ;
1142+ WOLFSSL * ssl = (WOLFSSL * )(uintptr_t )sslPtr ;
1143+
1144+ jclass excClass ;
1145+ jclass buffClass ;
1146+ jmethodID positionMeth ;
1147+ jmethodID limitMeth ;
1148+ jmethodID hasArrayMeth ;
1149+ jmethodID arrayMeth ;
1150+ jmethodID setPositionMeth ;
1151+
1152+ jint position ;
1153+ jint limit ;
1154+ jboolean hasArray ;
1155+ jbyteArray bufArr ;
1156+
1157+ (void )jcl ;
1158+
1159+ if (jenv == NULL || ssl == NULL || buf == NULL ) {
1160+ return BAD_FUNC_ARG ;
1161+ }
1162+
1163+ if (length > 0 ) {
1164+ /* Get WolfSSLException class */
1165+ excClass = (* jenv )-> FindClass (jenv , "com/wolfssl/WolfSSLException" );
1166+ if ((* jenv )-> ExceptionOccurred (jenv )) {
1167+ (* jenv )-> ExceptionDescribe (jenv );
1168+ (* jenv )-> ExceptionClear (jenv );
1169+ return -1 ;
10431170 }
10441171
1045- do {
1046- /* lock mutex around session I/O before read attempt */
1047- if (wc_LockMutex (jniSessLock ) != 0 ) {
1048- size = WOLFSSL_FAILURE ;
1049- break ;
1050- }
1172+ /* Get ByteBuffer class */
1173+ buffClass = (* jenv )-> GetObjectClass (jenv , buf );
1174+ if (buffClass == NULL ) {
1175+ (* jenv )-> ThrowNew (jenv , excClass ,
1176+ "Failed to find ByteBuffer class in native read()" );
1177+ return -1 ;
1178+ }
10511179
1052- size = wolfSSL_read (ssl , data + offset , length );
1053- err = wolfSSL_get_error (ssl , size );
1180+ /* Get ByteBuffer position */
1181+ positionMeth = (* jenv )-> GetMethodID (jenv , buffClass , "position" , "()I" );
1182+ if (positionMeth == NULL ) {
1183+ if ((* jenv )-> ExceptionOccurred (jenv )) {
1184+ (* jenv )-> ExceptionDescribe (jenv );
1185+ (* jenv )-> ExceptionClear (jenv );
1186+ }
1187+ (* jenv )-> ThrowNew (jenv , excClass ,
1188+ "Failed to find ByteBuffer position() method in native read()" );
1189+ return -1 ;
1190+ }
1191+ position = (* jenv )-> CallIntMethod (jenv , buf , positionMeth );
10541192
1055- /* unlock mutex around session I/O after read attempt */
1056- if (wc_UnLockMutex (jniSessLock ) != 0 ) {
1057- size = WOLFSSL_FAILURE ;
1058- break ;
1193+ /* Get ByteBuffer limit */
1194+ limitMeth = (* jenv )-> GetMethodID (jenv , buffClass , "limit" , "()I" );
1195+ if (limitMeth == NULL ) {
1196+ if ((* jenv )-> ExceptionOccurred (jenv )) {
1197+ (* jenv )-> ExceptionDescribe (jenv );
1198+ (* jenv )-> ExceptionClear (jenv );
10591199 }
1200+ (* jenv )-> ThrowNew (jenv , excClass ,
1201+ "Failed to find ByteBuffer limit() method in native read()" );
1202+ return -1 ;
1203+ }
1204+ limit = (* jenv )-> CallIntMethod (jenv , buf , limitMeth );
10601205
1061- if (size < 0 && ((err == SSL_ERROR_WANT_READ ) || \
1062- (err == SSL_ERROR_WANT_WRITE ))) {
1206+ /* Get and call ByteBuffer.hasArray() before calling array() */
1207+ hasArrayMeth = (* jenv )-> GetMethodID (jenv , buffClass , "hasArray" , "()Z" );
1208+ if (hasArrayMeth == NULL ) {
1209+ if ((* jenv )-> ExceptionOccurred (jenv )) {
1210+ (* jenv )-> ExceptionDescribe (jenv );
1211+ (* jenv )-> ExceptionClear (jenv );
1212+ }
1213+ (* jenv )-> ThrowNew (jenv , excClass ,
1214+ "Failed to find ByteBuffer hasArray() method in native read()" );
1215+ return -1 ;
1216+ }
10631217
1064- sockfd = wolfSSL_get_fd (ssl );
1065- if (sockfd == -1 ) {
1066- /* For I/O that does not use sockets, sockfd may be -1,
1067- * skip try to call select() */
1068- break ;
1069- }
1218+ /* ByteBuffer.hasArray() does not throw any exceptions */
1219+ hasArray = (* jenv )-> CallBooleanMethod (jenv , buf , hasArrayMeth );
1220+ if (!hasArray ) {
1221+ (* jenv )-> ThrowNew (jenv , excClass ,
1222+ "ByteBuffer.hasArray() is false in native read()" );
1223+ return BAD_FUNC_ARG ;
1224+ }
10701225
1071- if (err == SSL_ERROR_WANT_READ ) {
1072- pollRx = 1 ;
1073- }
1074- else if (err == SSL_ERROR_WANT_WRITE ) {
1075- pollTx = 1 ;
1076- }
1226+ /* Only read up to maximum space we have in this ByteBuffer */
1227+ maxOutputSz = (limit - position );
1228+ if (outSz > maxOutputSz ) {
1229+ outSz = maxOutputSz ;
1230+ }
10771231
1078- #if defined(WOLFJNI_USE_IO_SELECT ) || defined(USE_WINDOWS_API )
1079- ret = socketSelect (sockfd , (int )timeout , pollRx );
1080- #else
1081- ret = socketPoll (sockfd , (int )timeout , pollRx , pollTx );
1082- #endif
1083- if ((ret == WOLFJNI_IO_EVENT_RECV_READY ) ||
1084- (ret == WOLFJNI_IO_EVENT_SEND_READY )) {
1085- /* loop around and try wolfSSL_read() again */
1086- continue ;
1087- } else {
1088- /* Java will throw SocketTimeoutException or
1089- * SocketException if ret equals
1090- * WOLFJNI_IO_EVENT_TIMEOUT, WOLFJNI_IO_EVENT_FD_CLOSED
1091- * WOLFJNI_IO_EVENT_ERROR, WOLFJNI_IO_EVENT_POLLHUP or
1092- * WOLFJNI_IO_EVENT_FAIL */
1093- size = ret ;
1094- break ;
1095- }
1232+ /* Get reference to underlying byte[] from ByteBuffer */
1233+ arrayMeth = (* jenv )-> GetMethodID (jenv , buffClass , "array" , "()[B" );
1234+ if (arrayMeth == NULL ) {
1235+ if ((* jenv )-> ExceptionOccurred (jenv )) {
1236+ (* jenv )-> ExceptionDescribe (jenv );
1237+ (* jenv )-> ExceptionClear (jenv );
10961238 }
1239+ (* jenv )-> ThrowNew (jenv , excClass ,
1240+ "Failed to find ByteBuffer array() method in native read()" );
1241+ return -1 ;
1242+ }
1243+ bufArr = (jbyteArray )(* jenv )-> CallObjectMethod (jenv , buf , arrayMeth );
10971244
1098- } while (err == SSL_ERROR_WANT_WRITE || err == SSL_ERROR_WANT_READ );
1245+ /* Get array elements */
1246+ data = (byte * )(* jenv )-> GetByteArrayElements (jenv , bufArr , NULL );
1247+ if ((* jenv )-> ExceptionOccurred (jenv )) {
1248+ (* jenv )-> ExceptionDescribe (jenv );
1249+ (* jenv )-> ExceptionClear (jenv );
1250+ (* jenv )-> ThrowNew (jenv , excClass ,
1251+ "Exception when calling ByteBuffer.array() in native read()" );
1252+ return -1 ;
1253+ }
1254+
1255+
1256+ if (data != NULL ) {
1257+ size = SSLReadNonblockingWithSelectPoll (ssl , data + position ,
1258+ maxOutputSz , (int )timeout );
10991259
1100- /* JNI_COMMIT commits the data but does not free the local array
1101- * 0 is used here to both commit and free */
1102- (* jenv )-> ReleaseByteArrayElements (jenv , raw , (jbyte * )data , 0 );
1260+ /* Relase array elements */
1261+ if (size < 0 ) {
1262+ (* jenv )-> ReleaseByteArrayElements (jenv , bufArr , (jbyte * )data ,
1263+ JNI_ABORT );
1264+ }
1265+ else {
1266+ /* JNI_COMMIT commits the data but does not free the local array
1267+ * 0 is used here to both commit and free */
1268+ (* jenv )-> ReleaseByteArrayElements (jenv , bufArr ,
1269+ (jbyte * )data , 0 );
1270+
1271+ /* Update ByteBuffer position() based on bytes written */
1272+ setPositionMeth = (* jenv )-> GetMethodID (jenv , buffClass ,
1273+ "position" , "(I)Ljava/nio/Buffer;" );
1274+ if (setPositionMeth == NULL ) {
1275+ if ((* jenv )-> ExceptionOccurred (jenv )) {
1276+ (* jenv )-> ExceptionDescribe (jenv );
1277+ (* jenv )-> ExceptionClear (jenv );
1278+ }
1279+ (* jenv )-> ThrowNew (jenv , excClass ,
1280+ "Failed to set ByteBuffer position() from "
1281+ "native read()" );
1282+ size = -1 ;
1283+ }
1284+ else {
1285+ (* jenv )-> CallVoidMethod (jenv , buf , setPositionMeth ,
1286+ position + size );
1287+ }
1288+ }
1289+ }
11031290 }
11041291
11051292 return size ;
0 commit comments