Merge pull request #246 from cconlon/socketCloseInterruptsWriteRead
JSSE: calling SSLSocket.close() should interrupt threads blocked in select()/poll()pull/249/head
commit
d56fa67109
|
@ -15,6 +15,9 @@ on:
|
|||
wolfssl_configure:
|
||||
required: true
|
||||
type: string
|
||||
javash_cflags:
|
||||
required: false
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
build_wolfssljni:
|
||||
|
@ -51,7 +54,7 @@ jobs:
|
|||
echo "LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$GITHUB_WORKSPACE/build-dir/lib" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Build JNI library
|
||||
run: ./java.sh $GITHUB_WORKSPACE/build-dir
|
||||
run: CFLAGS=${{ inputs.javah_cflags }} ./java.sh $GITHUB_WORKSPACE/build-dir
|
||||
- name: Build JAR (ant)
|
||||
run: ant
|
||||
- name: Run Java tests (ant test)
|
||||
|
|
|
@ -120,6 +120,27 @@ jobs:
|
|||
jdk_version: ${{ matrix.jdk_version }}
|
||||
wolfssl_configure: ${{ matrix.wolfssl_configure }}
|
||||
|
||||
# -------------------- WOLFJNI_USE_IO_SELECT sanity check --------------------
|
||||
# Only check one Linux and Mac JDK version as a sanity check.
|
||||
# Using Zulu, but this can be expanded if needed.
|
||||
linux-zulu-ioselect:
|
||||
strategy:
|
||||
matrix:
|
||||
os: [ 'ubuntu-latest', 'macos-latest' ]
|
||||
jdk_version: [ '11' ]
|
||||
wolfssl_configure: [
|
||||
'--enable-jni',
|
||||
]
|
||||
javash_cflags: [ '-DWOLFJNI_USE_IO_SELECT' ]
|
||||
name: ${{ matrix.os }} (Zulu JDK ${{ matrix.jdk_version }}, ${{ matrix.wolfssl_configure}}, ${{ matrix.javash_cflags }})
|
||||
uses: ./.github/workflows/linux-common.yml
|
||||
with:
|
||||
os: ${{ matrix.os }}
|
||||
jdk_distro: "zulu"
|
||||
jdk_version: ${{ matrix.jdk_version }}
|
||||
wolfssl_configure: ${{ matrix.wolfssl_configure }}
|
||||
javash_cflags: ${{ matrix.javash_cflags }}
|
||||
|
||||
# ------------------ Facebook Infer static analysis -------------------
|
||||
# Run Facebook infer over PR code, only running on Linux with one
|
||||
# JDK/version for now.
|
||||
|
|
38
README.md
38
README.md
|
@ -108,6 +108,44 @@ $ ./examples/provider/ServerJSSE.sh
|
|||
$ ./examples/provider/ClientJSSE.sh
|
||||
```
|
||||
|
||||
### java.sh Script Options
|
||||
|
||||
The `java.sh` script compiles the native JNI sources into a shared library named
|
||||
either `libwolfssljni.so` (Linux/Unix) or `libwolfssljni.dylib` (MacOS).
|
||||
Compiling on Linux/Unix and Mac OSX are currently supported.
|
||||
|
||||
This script will attempt to auto-detect the `JAVA_HOME` location if not set.
|
||||
To explicitly use a Java home location, set the `JAVA_HOME` environment variable
|
||||
prior to running this script.
|
||||
|
||||
This script will try to link against a wolfSSL library installed to the
|
||||
default location of `/usr/local`. This script accepts two arguments on the
|
||||
command line. The first argument can point to a custom wolfSSL installation
|
||||
location. A custom install location would match the directory set at wolfSSL
|
||||
`./configure --prefix=<DIR>`.
|
||||
|
||||
The second argument represents the wolfSSL library name that should be
|
||||
linked against. This is helpful if a non-standard library name has been
|
||||
used with wolfSSL, for example the `./configure --with-libsuffix` option
|
||||
has been used to add a suffix to the wolfSSL library name. Note that to
|
||||
use this argument, an installation location must be specified via the
|
||||
first argument.
|
||||
|
||||
For example, if wolfSSL was configured with `--with-libsuffix=jsse`, then
|
||||
this script could be called like so using the default installation
|
||||
path of `/usr/local`:
|
||||
|
||||
```
|
||||
java.sh /usr/local wolfssljsse
|
||||
```
|
||||
|
||||
`java.sh` can use preset `CFLAGS` defines, if set in the environment variable
|
||||
prior to running the script, for example:
|
||||
|
||||
```
|
||||
CFLAGS=-DWOLFJNI_USE_IO_SELECT java.sh
|
||||
```
|
||||
|
||||
## Building with Maven
|
||||
|
||||
wolfJSSE supports building and packaging with Maven, for those projects that
|
||||
|
|
26
java.sh
26
java.sh
|
@ -75,7 +75,6 @@ if [ "$OS" == "Darwin" ] ; then
|
|||
javaIncludes="-I$javaHome/include -I$javaHome/include/darwin -I$WOLFSSL_INSTALL_DIR/include"
|
||||
javaLibs="-dynamiclib"
|
||||
jniLibName="libwolfssljni.dylib"
|
||||
cflags=""
|
||||
elif [ "$OS" == "Linux" ] ; then
|
||||
echo " Detected Linux host OS"
|
||||
if [ -z $javaHome ]; then
|
||||
|
@ -88,7 +87,6 @@ elif [ "$OS" == "Linux" ] ; then
|
|||
javaIncludes="-I$javaHome/include -I$javaHome/include/linux -I$WOLFSSL_INSTALL_DIR/include"
|
||||
javaLibs="-shared"
|
||||
jniLibName="libwolfssljni.so"
|
||||
cflags=""
|
||||
if [ "$ARCH" == "x86_64" ] ; then
|
||||
fpic="-fPIC"
|
||||
else
|
||||
|
@ -108,18 +106,18 @@ then
|
|||
mkdir ./lib
|
||||
fi
|
||||
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSL.c -o ./native/com_wolfssl_WolfSSL.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLSession.c -o ./native/com_wolfssl_WolfSSLSession.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLContext.c -o ./native/com_wolfssl_WolfSSLContext.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_RSA.c -o ./native/com_wolfssl_wolfcrypt_RSA.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_ECC.c -o ./native/com_wolfssl_wolfcrypt_ECC.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_wolfcrypt_EccKey.c -o ./native/com_wolfssl_wolfcrypt_EccKey.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertManager.c -o ./native/com_wolfssl_WolfSSLCertManager.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertRequest.c -o ./native/com_wolfssl_WolfSSLCertRequest.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLCertificate.c -o ./native/com_wolfssl_WolfSSLCertificate.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLX509Name.c -o ./native/com_wolfssl_WolfSSLX509Name.o $javaIncludes
|
||||
gcc -Wall -c $fpic $cflags ./native/com_wolfssl_WolfSSLX509StoreCtx.c -o ./native/com_wolfssl_WolfSSLX509StoreCtx.o $javaIncludes
|
||||
gcc -Wall $javaLibs $cflags -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_wolfcrypt_RSA.o ./native/com_wolfssl_wolfcrypt_ECC.o ./native/com_wolfssl_wolfcrypt_EccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertRequest.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSL.c -o ./native/com_wolfssl_WolfSSL.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLSession.c -o ./native/com_wolfssl_WolfSSLSession.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLContext.c -o ./native/com_wolfssl_WolfSSLContext.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_wolfcrypt_RSA.c -o ./native/com_wolfssl_wolfcrypt_RSA.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_wolfcrypt_ECC.c -o ./native/com_wolfssl_wolfcrypt_ECC.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_wolfcrypt_EccKey.c -o ./native/com_wolfssl_wolfcrypt_EccKey.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertManager.c -o ./native/com_wolfssl_WolfSSLCertManager.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertRequest.c -o ./native/com_wolfssl_WolfSSLCertRequest.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLCertificate.c -o ./native/com_wolfssl_WolfSSLCertificate.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLX509Name.c -o ./native/com_wolfssl_WolfSSLX509Name.o $javaIncludes
|
||||
gcc -Wall -c $fpic $CFLAGS ./native/com_wolfssl_WolfSSLX509StoreCtx.c -o ./native/com_wolfssl_WolfSSLX509StoreCtx.o $javaIncludes
|
||||
gcc -Wall $javaLibs $CFLAGS -o ./lib/$jniLibName ./native/com_wolfssl_WolfSSL.o ./native/com_wolfssl_WolfSSLSession.o ./native/com_wolfssl_WolfSSLContext.o ./native/com_wolfssl_wolfcrypt_RSA.o ./native/com_wolfssl_wolfcrypt_ECC.o ./native/com_wolfssl_wolfcrypt_EccKey.o ./native/com_wolfssl_WolfSSLCertManager.o ./native/com_wolfssl_WolfSSLCertRequest.o ./native/com_wolfssl_WolfSSLCertificate.o ./native/com_wolfssl_WolfSSLX509Name.o ./native/com_wolfssl_WolfSSLX509StoreCtx.o -L$WOLFSSL_INSTALL_DIR/lib -L$WOLFSSL_INSTALL_DIR/lib64 -l$WOLFSSL_LIBNAME
|
||||
if [ $? != 0 ]; then
|
||||
echo "Error creating native JNI library"
|
||||
exit 1
|
||||
|
|
|
@ -72,8 +72,17 @@ static jobject g_crlCbIfaceObj;
|
|||
* function calls. Stored inside WOLFSSL app data, set with
|
||||
* wolfSSL_set_app_data(), retrieved with wolfSSL_get_app_data().
|
||||
* Global callback objects are created with NewGlobalRef(), then freed
|
||||
* inside freeSSL() with DeleteGlobalRef(). */
|
||||
* inside freeSSL() with DeleteGlobalRef().
|
||||
*
|
||||
* interruptFds[2] is a pipe() used for non-Windows platforms. This pipe is
|
||||
* used to interrupt threads blocked inside select()/poll() when a separate
|
||||
* Java thread calls close() on the SSLSocket. */
|
||||
typedef struct SSLAppData {
|
||||
int threadsInPoll; /* number of threads in poll/select() */
|
||||
#ifndef USE_WINDOWS_API
|
||||
int interruptFds[2]; /* pipe for interrupting socketSelect() */
|
||||
wolfSSL_Mutex* pollCountLock; /* lock around threadsInPoll */
|
||||
#endif
|
||||
wolfSSL_Mutex* jniSessLock; /* WOLFSSL session lock */
|
||||
jobject* g_verifySSLCbIfaceObj; /* Java verify callback [global ref] */
|
||||
} SSLAppData;
|
||||
|
@ -191,13 +200,116 @@ int NativeSSLVerifyCallback(int preverify_ok, WOLFSSL_X509_STORE_CTX* store)
|
|||
return retval;
|
||||
}
|
||||
|
||||
#ifndef USE_WINDOWS_API
|
||||
|
||||
/* Close interrupt pipe() descriptors and reset back to -1. */
|
||||
static void closeInterruptPipe(SSLAppData* appData)
|
||||
{
|
||||
if (appData != NULL) {
|
||||
if (appData->interruptFds[0] != -1) {
|
||||
close(appData->interruptFds[0]);
|
||||
appData->interruptFds[0] = -1;
|
||||
}
|
||||
if (appData->interruptFds[1] != -1) {
|
||||
close(appData->interruptFds[1]);
|
||||
appData->interruptFds[1] = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Signal to threads blocked in select() or poll() to wake up, by writing
|
||||
* one byte to the appData.interruptFds[1] pipe. */
|
||||
static void writeToInterruptPipe(SSLAppData* appData)
|
||||
{
|
||||
if (appData != NULL) {
|
||||
if (appData->interruptFds[1] != -1) {
|
||||
write(appData->interruptFds[1], "1", 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* !USE_WINDOWS_API */
|
||||
|
||||
/* Return number of threads waiting in poll()/select() */
|
||||
static int threadsWaitingInPollSelect(SSLAppData* appData)
|
||||
{
|
||||
int ret = 0;
|
||||
#ifndef USE_WINDOWS_API
|
||||
wolfSSL_Mutex* pollCountLock = NULL;
|
||||
|
||||
if (appData != NULL) {
|
||||
pollCountLock = appData->pollCountLock;
|
||||
if (pollCountLock != NULL) {
|
||||
if (wc_LockMutex(pollCountLock) == 0) {
|
||||
ret = appData->threadsInPoll;
|
||||
wc_UnLockMutex(pollCountLock);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void incrementThreadPollCount(SSLAppData* appData)
|
||||
{
|
||||
#ifndef USE_WINDOWS_API
|
||||
wolfSSL_Mutex* pollCountLock = NULL;
|
||||
|
||||
if (appData == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pollCountLock = appData->pollCountLock;
|
||||
if (pollCountLock == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wc_LockMutex(pollCountLock) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
appData->threadsInPoll++;
|
||||
|
||||
wc_UnLockMutex(pollCountLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
static void decrementThreadPollCount(SSLAppData* appData)
|
||||
{
|
||||
#ifndef USE_WINDOWS_API
|
||||
wolfSSL_Mutex* pollCountLock = NULL;
|
||||
|
||||
if (appData == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
pollCountLock = appData->pollCountLock;
|
||||
if (pollCountLock == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (wc_LockMutex(pollCountLock) != 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (appData->threadsInPoll > 0) {
|
||||
appData->threadsInPoll--;
|
||||
}
|
||||
|
||||
wc_UnLockMutex(pollCountLock);
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
|
||||
(JNIEnv* jenv, jobject jcl, jlong ctx)
|
||||
(JNIEnv* jenv, jobject jcl, jlong ctx, jboolean withIOPipe)
|
||||
{
|
||||
int ret;
|
||||
jlong sslPtr = 0;
|
||||
jobject* g_cachedSSLObj = NULL;
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
#ifndef USE_WINDOWS_API
|
||||
wolfSSL_Mutex* pollCountLock = NULL;
|
||||
#endif
|
||||
SSLAppData* appData = NULL;
|
||||
|
||||
if (jenv == NULL) {
|
||||
|
@ -251,11 +363,71 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
|
|||
wc_InitMutex(jniSessLock);
|
||||
appData->jniSessLock = jniSessLock;
|
||||
|
||||
/* set up interrupt pipe for SSLSocket.close() to use if/when needed.
|
||||
* currently only non-Windows platforms supported due to Windows not
|
||||
* supporting direct/same pipe() operation. Make read pipe non
|
||||
* blocking since byte read from it could have already been taken
|
||||
* out by either reader/writer thread before the other has a chance
|
||||
* to read it. But, we only use it for waking us up and don't care
|
||||
* much about actually reading the byte passed over the pipe. */
|
||||
appData->threadsInPoll = 0;
|
||||
#ifndef USE_WINDOWS_API
|
||||
pollCountLock = (wolfSSL_Mutex*)XMALLOC(sizeof(wolfSSL_Mutex), NULL,
|
||||
DYNAMIC_TYPE_TMP_BUFFER);
|
||||
if (pollCountLock == NULL) {
|
||||
printf("error mallocing pollCountLock in newSSL for SSLAppData\n");
|
||||
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
|
||||
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
wc_InitMutex(pollCountLock);
|
||||
appData->pollCountLock = pollCountLock;
|
||||
|
||||
appData->interruptFds[0] = -1;
|
||||
appData->interruptFds[1] = -1;
|
||||
|
||||
if (withIOPipe == JNI_TRUE) {
|
||||
ret = pipe(appData->interruptFds);
|
||||
if (ret == -1) {
|
||||
printf("error setting up pipe() for interruptFds[] in newSSL\n");
|
||||
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
|
||||
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
|
||||
ret = fcntl(appData->interruptFds[0], F_SETFL,
|
||||
fcntl(appData->interruptFds[0], F_GETFL, 0) | O_NONBLOCK);
|
||||
if (ret < 0) {
|
||||
printf("error setting interruptFds[0] non-blocking in newSSL\n");
|
||||
closeInterruptPipe(appData);
|
||||
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
|
||||
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
|
||||
return SSL_FAILURE;
|
||||
}
|
||||
}
|
||||
#endif /* !USE_WINDOWS_API */
|
||||
|
||||
/* cache associated WolfSSLSession jobject in native WOLFSSL */
|
||||
ret = wolfSSL_set_jobject((WOLFSSL*)(uintptr_t)sslPtr, g_cachedSSLObj);
|
||||
if (ret != SSL_SUCCESS) {
|
||||
printf("error storing jobject in wolfSSL native session\n");
|
||||
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
|
||||
#ifndef USE_WINDOWS_API
|
||||
closeInterruptPipe(appData);
|
||||
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
wolfSSL_free((WOLFSSL*)(uintptr_t)sslPtr);
|
||||
|
@ -267,6 +439,10 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
|
|||
(WOLFSSL*)(uintptr_t)sslPtr, appData) != SSL_SUCCESS) {
|
||||
printf("error setting WOLFSSL app data in newSSL\n");
|
||||
(*jenv)->DeleteGlobalRef(jenv, *g_cachedSSLObj);
|
||||
#ifndef USE_WINDOWS_API
|
||||
closeInterruptPipe(appData);
|
||||
XFREE(pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
#endif
|
||||
XFREE(jniSessLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
XFREE(g_cachedSSLObj, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
|
@ -637,16 +813,21 @@ enum {
|
|||
* supported, since not supported on Java Socket.
|
||||
* @param rx set to 1 to monitor readability on socket descriptor,
|
||||
* otherwise 0 to monitor writability
|
||||
* @param shutdown Is this being called from shutdownSSL()? Don't select
|
||||
* on interruptFds in that case, since we already know
|
||||
* we are closing in that case.
|
||||
*
|
||||
* @return possible return values are:
|
||||
* WOLFJNI_IO_EVENT_FAIL
|
||||
* WOLFJNI_IO_EVENT_ERROR
|
||||
* WOLFJNI_IO_EVENT_FD_CLOSED
|
||||
* WOLFJNI_IO_EVENT_TIMEOUT
|
||||
* WOLFJNI_IO_EVENT_RECV_READY
|
||||
* WOLFJNI_IO_EVENT_SEND_READY
|
||||
* WOLFJNI_IO_EVENT_INVALID_TIMEOUT
|
||||
*/
|
||||
static int socketSelect(int sockfd, int timeout_ms, int rx)
|
||||
static int socketSelect(SSLAppData* appData, int sockfd, int timeout_ms, int rx,
|
||||
int shutdown)
|
||||
{
|
||||
fd_set fds, errfds;
|
||||
fd_set* recvfds = NULL;
|
||||
|
@ -654,20 +835,39 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
|
|||
int nfds = sockfd + 1;
|
||||
int result = 0;
|
||||
struct timeval timeout;
|
||||
#ifndef USE_WINDOWS_API
|
||||
char tmpBuf[1];
|
||||
#endif
|
||||
|
||||
/* Java Socket does not support negative timeouts, sanitize */
|
||||
if (timeout_ms < 0) {
|
||||
return WOLFJNI_IO_EVENT_INVALID_TIMEOUT;
|
||||
}
|
||||
|
||||
if (appData == NULL) {
|
||||
return WOLFJNI_IO_EVENT_ERROR;
|
||||
}
|
||||
|
||||
#ifndef USE_WINDOWS_API
|
||||
do {
|
||||
#endif
|
||||
timeout.tv_sec = timeout_ms / 1000;
|
||||
timeout.tv_usec = (timeout_ms % 1000) * 1000;
|
||||
|
||||
/* file/socket descriptors */
|
||||
FD_ZERO(&fds);
|
||||
FD_SET(sockfd, &fds);
|
||||
#ifndef USE_WINDOWS_API
|
||||
if ((shutdown == 0) && (appData->interruptFds[0] != -1)) {
|
||||
FD_SET(appData->interruptFds[0], &fds);
|
||||
/* nfds should be set to the highest number descriptor plus 1 */
|
||||
if (appData->interruptFds[0] > sockfd) {
|
||||
nfds = appData->interruptFds[0] + 1;
|
||||
}
|
||||
}
|
||||
#endif /* !USE_WINDOWS_API */
|
||||
|
||||
/* error descriptors */
|
||||
FD_ZERO(&errfds);
|
||||
FD_SET(sockfd, &errfds);
|
||||
|
||||
|
@ -677,11 +877,13 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
|
|||
sendfds = &fds;
|
||||
}
|
||||
|
||||
incrementThreadPollCount(appData);
|
||||
if (timeout_ms == 0) {
|
||||
result = select(nfds, recvfds, sendfds, &errfds, NULL);
|
||||
} else {
|
||||
result = select(nfds, recvfds, sendfds, &errfds, &timeout);
|
||||
}
|
||||
decrementThreadPollCount(appData);
|
||||
|
||||
if (result == 0) {
|
||||
return WOLFJNI_IO_EVENT_TIMEOUT;
|
||||
|
@ -692,9 +894,26 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
|
|||
} else {
|
||||
return WOLFJNI_IO_EVENT_SEND_READY;
|
||||
}
|
||||
} else if (FD_ISSET(sockfd, &errfds)) {
|
||||
}
|
||||
else if (FD_ISSET(sockfd, &errfds)) {
|
||||
return WOLFJNI_IO_EVENT_ERROR;
|
||||
}
|
||||
#ifndef USE_WINDOWS_API
|
||||
else if ((shutdown == 0) && (appData->interruptFds[0] != -1) &&
|
||||
(FD_ISSET(appData->interruptFds[0], &fds))) {
|
||||
/* We got interrupted by our interrupt fd, due to a Java
|
||||
* thread calling SSLSocket.close(). Try to read byte that
|
||||
* was placed on our interruptFds[0] descriptor, but not
|
||||
* an error if not there. Another read/write() may have
|
||||
* already read it off. We just want to be interrupted,
|
||||
* byte value does not matter. */
|
||||
do {
|
||||
read(appData->interruptFds[0], tmpBuf, 1);
|
||||
} while (errno == EINTR);
|
||||
|
||||
return WOLFJNI_IO_EVENT_FD_CLOSED;
|
||||
}
|
||||
#endif /* !USE_WINDOWS_API */
|
||||
}
|
||||
|
||||
#ifndef USE_WINDOWS_API
|
||||
|
@ -725,6 +944,9 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
|
|||
* otherwise 0 to ignore readability events
|
||||
* @param tx set to 1 to monitor writability on socket descriptor,
|
||||
* otherwise 0 to ignore writability events
|
||||
* @param shutdown Is this being called from shutdownSSL()? Don't poll
|
||||
* on interruptFds in that case, since we already know
|
||||
* we are closing in that case.
|
||||
*
|
||||
* @return possible return values are:
|
||||
* WOLFJNI_IO_EVENT_FAIL
|
||||
|
@ -736,11 +958,18 @@ static int socketSelect(int sockfd, int timeout_ms, int rx)
|
|||
* WOLFJNI_IO_EVENT_POLLHUP
|
||||
* WOLFJNI_IO_EVENT_INVALID_TIMEOUT
|
||||
*/
|
||||
static int socketPoll(int sockfd, int timeout_ms, int rx, int tx)
|
||||
static int socketPoll(SSLAppData* appData, int sockfd, int timeout_ms,
|
||||
int rx, int tx, int shutdown)
|
||||
{
|
||||
int ret;
|
||||
int nfds = 2;
|
||||
int timeout;
|
||||
struct pollfd fds[1];
|
||||
struct pollfd fds[2];
|
||||
char tmpBuf[1];
|
||||
|
||||
if (appData == NULL) {
|
||||
return WOLFJNI_IO_EVENT_ERROR;
|
||||
}
|
||||
|
||||
/* Sanitize timeout and convert from Java to poll() expectations */
|
||||
timeout = timeout_ms;
|
||||
|
@ -750,35 +979,62 @@ static int socketPoll(int sockfd, int timeout_ms, int rx, int tx)
|
|||
timeout = -1;
|
||||
}
|
||||
|
||||
/* fd for socket I/O */
|
||||
fds[0].fd = sockfd;
|
||||
fds[0].events = 0;
|
||||
if (tx) {
|
||||
fds[0].events |= POLLOUT;
|
||||
fds[0].events |= POLLOUT | POLLPRI;
|
||||
}
|
||||
if (rx) {
|
||||
fds[0].events |= POLLIN;
|
||||
fds[0].events |= POLLIN | POLLPRI;
|
||||
}
|
||||
|
||||
if ((shutdown == 0) && (appData->interruptFds[0] != -1)) {
|
||||
/* fd for interrupt / signaling SSLSocket.close() */
|
||||
fds[1].fd = appData->interruptFds[0];
|
||||
fds[1].events = POLLIN | POLLPRI;
|
||||
}
|
||||
else {
|
||||
nfds--;
|
||||
}
|
||||
|
||||
do {
|
||||
ret = poll(fds, 1, timeout);
|
||||
incrementThreadPollCount(appData);
|
||||
ret = poll(fds, nfds, timeout);
|
||||
decrementThreadPollCount(appData);
|
||||
if (ret == 0) {
|
||||
return WOLFJNI_IO_EVENT_TIMEOUT;
|
||||
|
||||
} else if (ret > 0) {
|
||||
if (fds[0].revents & POLLIN ||
|
||||
}
|
||||
else if (ret > 0) {
|
||||
if ((shutdown == 0) && (appData->interruptFds[0] != -1) &&
|
||||
(fds[1].revents & POLLIN)) {
|
||||
/* received data on interrupt pipe, read and return
|
||||
* that descriptor is closed (closing) */
|
||||
do {
|
||||
read(appData->interruptFds[0], tmpBuf, 1);
|
||||
} while (errno == EINTR);
|
||||
|
||||
return WOLFJNI_IO_EVENT_FD_CLOSED;
|
||||
}
|
||||
else if (fds[0].revents & POLLIN ||
|
||||
fds[0].revents & POLLPRI) { /* read possible */
|
||||
return WOLFJNI_IO_EVENT_RECV_READY;
|
||||
|
||||
} else if (fds[0].revents & POLLOUT) { /* write possible */
|
||||
}
|
||||
else if (fds[0].revents & POLLOUT) { /* write possible */
|
||||
return WOLFJNI_IO_EVENT_SEND_READY;
|
||||
|
||||
} else if (fds[0].revents & POLLNVAL) { /* fd not open */
|
||||
}
|
||||
else if (fds[0].revents & POLLNVAL) { /* fd not open */
|
||||
return WOLFJNI_IO_EVENT_FD_CLOSED;
|
||||
|
||||
} else if (fds[0].revents & POLLERR) { /* exceptional error */
|
||||
}
|
||||
else if (fds[0].revents & POLLERR) { /* exceptional error */
|
||||
return WOLFJNI_IO_EVENT_ERROR;
|
||||
|
||||
} else if (fds[0].revents & POLLHUP) { /* sock disconnected */
|
||||
}
|
||||
else if (fds[0].revents & POLLHUP) { /* sock disconnected */
|
||||
return WOLFJNI_IO_EVENT_POLLHUP;
|
||||
}
|
||||
}
|
||||
|
@ -795,7 +1051,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
|
|||
{
|
||||
int ret = 0, err = 0, sockfd = 0;
|
||||
int pollRx = 0;
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
int pollTx = 0;
|
||||
#endif
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
SSLAppData* appData = NULL;
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
|
@ -852,14 +1110,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_connect
|
|||
if (err == SSL_ERROR_WANT_READ) {
|
||||
pollRx = 1;
|
||||
}
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
pollTx = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
|
||||
ret = socketSelect(sockfd, (int)timeout, pollRx);
|
||||
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
|
||||
#else
|
||||
ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
|
||||
ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 0);
|
||||
#endif
|
||||
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
|
||||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
|
||||
|
@ -898,7 +1158,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
|
|||
byte* data = NULL;
|
||||
int ret = SSL_FAILURE, err, sockfd;
|
||||
int pollRx = 0;
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
int pollTx = 0;
|
||||
#endif
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
SSLAppData* appData = NULL;
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
|
@ -963,14 +1225,17 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_write
|
|||
if (err == SSL_ERROR_WANT_READ) {
|
||||
pollRx = 1;
|
||||
}
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
pollTx = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
|
||||
ret = socketSelect(sockfd, (int)timeout, pollRx);
|
||||
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
|
||||
#else
|
||||
ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
|
||||
ret = socketPoll(appData, sockfd, (int)timeout, pollRx,
|
||||
pollTx, 0);
|
||||
#endif
|
||||
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
|
||||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
|
||||
|
@ -1017,7 +1282,9 @@ static int SSLReadNonblockingWithSelectPoll(WOLFSSL* ssl, byte* out,
|
|||
{
|
||||
int size, ret, err, sockfd;
|
||||
int pollRx = 0;
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
int pollTx = 0;
|
||||
#endif
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
SSLAppData* appData = NULL;
|
||||
|
||||
|
@ -1065,14 +1332,16 @@ static int SSLReadNonblockingWithSelectPoll(WOLFSSL* ssl, byte* out,
|
|||
if (err == SSL_ERROR_WANT_READ) {
|
||||
pollRx = 1;
|
||||
}
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
pollTx = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
|
||||
ret = socketSelect(sockfd, timeout, pollRx);
|
||||
ret = socketSelect(appData, sockfd, timeout, pollRx, 0);
|
||||
#else
|
||||
ret = socketPoll(sockfd, timeout, pollRx, pollTx);
|
||||
ret = socketPoll(appData, sockfd, timeout, pollRx, pollTx, 0);
|
||||
#endif
|
||||
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
|
||||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
|
||||
|
@ -1152,7 +1421,7 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_read__JLjava_nio_ByteBuff
|
|||
jint position;
|
||||
jint limit;
|
||||
jboolean hasArray;
|
||||
jbyteArray bufArr;
|
||||
jbyteArray bufArr = NULL;
|
||||
|
||||
(void)jcl;
|
||||
|
||||
|
@ -1304,7 +1573,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
|||
{
|
||||
int ret = 0, err, sockfd;
|
||||
int pollRx = 0;
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
int pollTx = 0;
|
||||
#endif
|
||||
wolfSSL_Mutex* jniSessLock = NULL;
|
||||
SSLAppData* appData = NULL;
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
|
@ -1361,14 +1632,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_accept
|
|||
if (err == SSL_ERROR_WANT_READ) {
|
||||
pollRx = 1;
|
||||
}
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
pollTx = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
|
||||
ret = socketSelect(sockfd, (int)timeout, pollRx);
|
||||
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 0);
|
||||
#else
|
||||
ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
|
||||
ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 0);
|
||||
#endif
|
||||
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
|
||||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
|
||||
|
@ -1441,6 +1714,16 @@ JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_freeSSL
|
|||
XFREE(g_cachedVerifyCb, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
g_cachedVerifyCb = NULL;
|
||||
}
|
||||
#ifndef USE_WINDOWS_API
|
||||
if (appData->pollCountLock != NULL) {
|
||||
wc_FreeMutex(appData->pollCountLock);
|
||||
XFREE(appData->pollCountLock, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
appData->pollCountLock = NULL;
|
||||
}
|
||||
|
||||
/* close pipe() descriptors */
|
||||
closeInterruptPipe(appData);
|
||||
#endif
|
||||
/* free appData */
|
||||
XFREE(appData, NULL, DYNAMIC_TYPE_TMP_BUFFER);
|
||||
appData = NULL;
|
||||
|
@ -1553,7 +1836,9 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_shutdownSSL
|
|||
{
|
||||
int ret = 0, err, sockfd;
|
||||
int pollRx = 0;
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
int pollTx = 0;
|
||||
#endif
|
||||
wolfSSL_Mutex* jniSessLock;
|
||||
SSLAppData* appData = NULL;
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
|
@ -1610,14 +1895,16 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_shutdownSSL
|
|||
if (err == SSL_ERROR_WANT_READ) {
|
||||
pollRx = 1;
|
||||
}
|
||||
#if !defined(WOLFJNI_USE_IO_SELECT) && !defined(USE_WINDOWS_API)
|
||||
else if (err == SSL_ERROR_WANT_WRITE) {
|
||||
pollTx = 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
|
||||
ret = socketSelect(sockfd, (int)timeout, pollRx);
|
||||
ret = socketSelect(appData, sockfd, (int)timeout, pollRx, 1);
|
||||
#else
|
||||
ret = socketPoll(sockfd, (int)timeout, pollRx, pollTx);
|
||||
ret = socketPoll(appData, sockfd, (int)timeout, pollRx, pollTx, 1);
|
||||
#endif
|
||||
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
|
||||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
|
||||
|
@ -1822,11 +2109,11 @@ JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_get1Session
|
|||
|
||||
#if defined(WOLFJNI_USE_IO_SELECT) || defined(USE_WINDOWS_API)
|
||||
/* Default to select() on Windows or if WOLFJNI_USE_IO_SELECT */
|
||||
ret = socketSelect(sockfd,
|
||||
(int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1);
|
||||
#else
|
||||
ret = socketPoll(sockfd,
|
||||
ret = socketSelect(appData, sockfd,
|
||||
(int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1, 0);
|
||||
#else
|
||||
ret = socketPoll(appData, sockfd,
|
||||
(int)WOLFSSL_JNI_DEFAULT_PEEK_TIMEOUT, 1, 0, 0);
|
||||
#endif
|
||||
if ((ret == WOLFJNI_IO_EVENT_RECV_READY) ||
|
||||
(ret == WOLFJNI_IO_EVENT_SEND_READY)) {
|
||||
|
@ -3558,12 +3845,8 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getSide
|
|||
(void)jenv;
|
||||
(void)jcl;
|
||||
|
||||
#ifdef ATOMIC_USER
|
||||
/* wolfSSL checks ssl for NULL */
|
||||
return wolfSSL_GetSide((WOLFSSL*)(uintptr_t)ssl);
|
||||
#else
|
||||
return NOT_COMPILED_IN;
|
||||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_isTLSv1_11
|
||||
|
@ -5445,6 +5728,51 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_hasTicket
|
|||
#endif
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_interruptBlockedIO
|
||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
||||
{
|
||||
#ifndef USE_WINDOWS_API
|
||||
SSLAppData* appData = NULL;
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
#endif
|
||||
(void)jenv;
|
||||
(void)jcl;
|
||||
|
||||
#ifndef USE_WINDOWS_API
|
||||
/* get session mutex from SSL app data */
|
||||
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
|
||||
if (appData == NULL) {
|
||||
return WOLFSSL_FAILURE;
|
||||
}
|
||||
|
||||
/* signal any blocked threads in select()/poll() to wake up, so we
|
||||
* don't have a deadlock when trying to lock jniSessLock next */
|
||||
writeToInterruptPipe(appData);
|
||||
writeToInterruptPipe(appData);
|
||||
|
||||
#endif /* USE_WINDOWS_API */
|
||||
|
||||
return SSL_SUCCESS;
|
||||
}
|
||||
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getThreadsBlockedInPoll
|
||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
||||
{
|
||||
SSLAppData* appData = NULL;
|
||||
WOLFSSL* ssl = (WOLFSSL*)(uintptr_t)sslPtr;
|
||||
|
||||
(void)jenv;
|
||||
(void)jcl;
|
||||
|
||||
/* get session mutex from SSL app data */
|
||||
appData = (SSLAppData*)wolfSSL_get_app_data(ssl);
|
||||
if (appData == NULL) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return (jint)threadsWaitingInPollSelect(appData);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL Java_com_wolfssl_WolfSSLSession_setSSLIORecv
|
||||
(JNIEnv* jenv, jobject jcl, jlong sslPtr)
|
||||
{
|
||||
|
|
|
@ -10,10 +10,10 @@ extern "C" {
|
|||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
* Method: newSSL
|
||||
* Signature: (J)J
|
||||
* Signature: (JZ)J
|
||||
*/
|
||||
JNIEXPORT jlong JNICALL Java_com_wolfssl_WolfSSLSession_newSSL
|
||||
(JNIEnv *, jobject, jlong);
|
||||
(JNIEnv *, jobject, jlong, jboolean);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
|
@ -879,6 +879,22 @@ JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_useSupportedCurve
|
|||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_hasTicket
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
* Method: interruptBlockedIO
|
||||
* Signature: (J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_interruptBlockedIO
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
/*
|
||||
* Class: com_wolfssl_WolfSSLSession
|
||||
* Method: getThreadsBlockedInPoll
|
||||
* Signature: (J)I
|
||||
*/
|
||||
JNIEXPORT jint JNICALL Java_com_wolfssl_WolfSSLSession_getThreadsBlockedInPoll
|
||||
(JNIEnv *, jobject, jlong);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -102,6 +102,13 @@ public class WolfSSLSession {
|
|||
/**
|
||||
* Creates a new SSL/TLS session.
|
||||
*
|
||||
* Native session created also creates JNI SSLAppData for usage
|
||||
* internal to wolfSSL JNI. This constructor creates a default
|
||||
* pipe() to use for interrupting threads waiting in select()/poll()
|
||||
* when close() is called. To skip creation of this pipe() use
|
||||
* the WolfSSLSession(WolfSSLContext ctx, boolean setupIOPipe)
|
||||
* constructor with 'setupIOPipe' set to false.
|
||||
*
|
||||
* @param ctx WolfSSLContext object used to create SSL session.
|
||||
*
|
||||
* @throws com.wolfssl.WolfSSLException if session object creation
|
||||
|
@ -109,13 +116,61 @@ public class WolfSSLSession {
|
|||
*/
|
||||
public WolfSSLSession(WolfSSLContext ctx) throws WolfSSLException {
|
||||
|
||||
sslPtr = newSSL(ctx.getContextPtr());
|
||||
sslPtr = newSSL(ctx.getContextPtr(), true);
|
||||
if (sslPtr == 0) {
|
||||
throw new WolfSSLException("Failed to create SSL Object");
|
||||
}
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, sslPtr, "creating new WolfSSLSession");
|
||||
WolfSSLDebug.INFO, sslPtr,
|
||||
"creating new WolfSSLSession (with I/O pipe)");
|
||||
|
||||
synchronized (stateLock) {
|
||||
this.active = true;
|
||||
}
|
||||
|
||||
/* save context reference for I/O callbacks from JNI */
|
||||
this.ctx = ctx;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new SSL/TLS session.
|
||||
*
|
||||
* Native session created also creates JNI SSLAppData for usage
|
||||
* internal to wolfSSL JNI. A pipe() can be created internally to wolfSSL
|
||||
* JNI to use for interrupting threads waiting in select()/poll()
|
||||
* when close() is called. To skip creation of this pipe(), set
|
||||
* 'setupIOPipe' to false.
|
||||
*
|
||||
* It is generally recommended to have wolfSSL JNI create the native
|
||||
* pipe(), unless you will be operating over non-Socket I/O. For example,
|
||||
* when this WolfSSLSession is being created from the JSSE level
|
||||
* SSLEngine class.
|
||||
*
|
||||
* @param ctx WolfSSLContext object used to create SSL session.
|
||||
* @param setupIOPipe true to create internal IO pipe(), otherwise
|
||||
* false
|
||||
*
|
||||
* @throws com.wolfssl.WolfSSLException if session object creation
|
||||
* failed.
|
||||
*/
|
||||
public WolfSSLSession(WolfSSLContext ctx, boolean setupIOPipe)
|
||||
throws WolfSSLException {
|
||||
|
||||
sslPtr = newSSL(ctx.getContextPtr(), false);
|
||||
if (sslPtr == 0) {
|
||||
throw new WolfSSLException("Failed to create SSL Object");
|
||||
}
|
||||
|
||||
if (setupIOPipe) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, sslPtr,
|
||||
"creating new WolfSSLSession (with I/O pipe)");
|
||||
} else {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, sslPtr,
|
||||
"creating new WolfSSLSession (without I/O pipe)");
|
||||
}
|
||||
|
||||
synchronized (stateLock) {
|
||||
this.active = true;
|
||||
|
@ -240,7 +295,7 @@ public class WolfSSLSession {
|
|||
|
||||
/* ------------------ native method declarations -------------------- */
|
||||
|
||||
private native long newSSL(long ctx);
|
||||
private native long newSSL(long ctx, boolean withIOPipe);
|
||||
private native int setFd(long ssl, Socket sd, int type);
|
||||
private native int setFd(long ssl, DatagramSocket sd, int type);
|
||||
private native int useCertificateFile(long ssl, String file, int format);
|
||||
|
@ -357,6 +412,8 @@ public class WolfSSLSession {
|
|||
private native int set1SigAlgsList(long ssl, String list);
|
||||
private native int useSupportedCurve(long ssl, int name);
|
||||
private native int hasTicket(long session);
|
||||
private native int interruptBlockedIO(long ssl);
|
||||
private native int getThreadsBlockedInPoll(long ssl);
|
||||
|
||||
/* ------------------- session-specific methods --------------------- */
|
||||
|
||||
|
@ -4125,6 +4182,49 @@ public class WolfSSLSession {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interrupt native I/O operations blocked inside select()/poll().
|
||||
*
|
||||
* This is used by wolfJSSE when SSLSocket.close() is called, to wake up
|
||||
* threads that are blocked in select()/poll().
|
||||
*
|
||||
* @return WolfSSL.SSL_SUCCESS on success, negative on error.
|
||||
*
|
||||
* @throws IllegalStateException WolfSSLSession has been freed
|
||||
*/
|
||||
public synchronized int interruptBlockedIO()
|
||||
throws IllegalStateException {
|
||||
|
||||
confirmObjectIsActive();
|
||||
|
||||
/* Not synchronizing on sslLock, since we want to interrupt threads
|
||||
* blocked on I/O operations, which will already hold sslLock */
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, "entered interruptBlockedIO()");
|
||||
|
||||
return interruptBlockedIO(this.sslPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get count of threads currently blocked in select() or poll()
|
||||
* at the native JNI level.
|
||||
*
|
||||
* @return count of threads waiting in select() or poll()
|
||||
*
|
||||
* @throws IllegalStateException WolfSSLSession has been freed
|
||||
*/
|
||||
public synchronized int getThreadsBlockedInPoll()
|
||||
throws IllegalStateException {
|
||||
|
||||
confirmObjectIsActive();
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.Component.JNI,
|
||||
WolfSSLDebug.INFO, "entered getThreadsBlockedInPoll()");
|
||||
|
||||
return getThreadsBlockedInPoll(this.sslPtr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Use SNI name with this session.
|
||||
*
|
||||
|
|
|
@ -313,7 +313,7 @@ public class WolfSSLEngine extends SSLEngine {
|
|||
}
|
||||
|
||||
/* will throw WolfSSLException if issue creating WOLFSSL */
|
||||
ssl = new WolfSSLSession(ctx);
|
||||
ssl = new WolfSSLSession(ctx, false);
|
||||
|
||||
enableExtraDebug();
|
||||
enableIODebug();
|
||||
|
|
|
@ -2011,6 +2011,10 @@ public class WolfSSLSocket extends SSLSocket {
|
|||
handshakeFinished = this.handshakeComplete;
|
||||
}
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"signaling any blocked I/O threads to wake up");
|
||||
ssl.interruptBlockedIO();
|
||||
|
||||
/* Try TLS shutdown procedure, only if handshake has finished */
|
||||
if (ssl != null && handshakeFinished) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
|
@ -2036,12 +2040,15 @@ public class WolfSSLSocket extends SSLSocket {
|
|||
}
|
||||
|
||||
try {
|
||||
/* Use SO_LINGER value when calling
|
||||
* shutdown here, since we are closing the
|
||||
* socket */
|
||||
if (this.socket != null) {
|
||||
ret = ssl.shutdownSSL(
|
||||
this.socket.getSoTimeout());
|
||||
this.socket.getSoLinger());
|
||||
} else {
|
||||
ret = ssl.shutdownSSL(
|
||||
super.getSoTimeout());
|
||||
super.getSoLinger());
|
||||
}
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
|
@ -2065,9 +2072,7 @@ public class WolfSSLSocket extends SSLSocket {
|
|||
/* Release native verify callback (JNI global) */
|
||||
this.EngineHelper.unsetVerifyCallback();
|
||||
|
||||
/* Connection is closed, free native WOLFSSL session
|
||||
* to release native memory earlier than garbage
|
||||
* collector might with finalize(). */
|
||||
/* Close ConsumedRecvCtx data stream */
|
||||
Object readCtx = this.ssl.getIOReadCtx();
|
||||
if (readCtx != null &&
|
||||
readCtx instanceof ConsumedRecvCtx) {
|
||||
|
@ -2076,14 +2081,6 @@ public class WolfSSLSocket extends SSLSocket {
|
|||
"calling ConsumedRecvCtx.closeDataStreams()");
|
||||
rctx.closeDataStreams();
|
||||
}
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"calling this.ssl.freeSSL()");
|
||||
this.ssl.freeSSL();
|
||||
this.ssl = null;
|
||||
|
||||
/* Reset internal WolfSSLEngineHelper to null */
|
||||
this.EngineHelper.clearObjectState();
|
||||
this.EngineHelper = null;
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"thread exiting handshakeLock (shutdown)");
|
||||
|
@ -2112,6 +2109,33 @@ public class WolfSSLSocket extends SSLSocket {
|
|||
this.outStream = null;
|
||||
}
|
||||
}
|
||||
|
||||
/* Free this.ssl here instead of above for use cases
|
||||
* where a SSLSocket is created then closed()'d before
|
||||
* connected or handshake is done. freeSSL() will
|
||||
* release interruptFds[] pipe() and free up descriptor. */
|
||||
synchronized (ioLock) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"thread got ioLock (freeSSL)");
|
||||
|
||||
/* Connection is closed, free native WOLFSSL session
|
||||
* to release native memory earlier than garbage
|
||||
* collector might with finalize(), if we don't
|
||||
* have any threads still waiting in poll/select. */
|
||||
if (this.ssl.getThreadsBlockedInPoll() == 0) {
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"calling this.ssl.freeSSL()");
|
||||
this.ssl.freeSSL();
|
||||
this.ssl = null;
|
||||
}
|
||||
|
||||
/* Reset internal WolfSSLEngineHelper to null */
|
||||
this.EngineHelper.clearObjectState();
|
||||
this.EngineHelper = null;
|
||||
|
||||
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
|
||||
"thread exiting ioLock (shutdown)");
|
||||
} /* ioLock */
|
||||
}
|
||||
|
||||
if (this.autoClose) {
|
||||
|
@ -2687,7 +2711,11 @@ public class WolfSSLSocket extends SSLSocket {
|
|||
throw e;
|
||||
|
||||
} catch (IllegalStateException e) {
|
||||
throw new IOException(e);
|
||||
/* SSLSocket.close() may have already called freeSSL(),
|
||||
* thus causing a 'WolfSSLSession object has been freed'
|
||||
* IllegalStateException to be thrown from
|
||||
* WolfSSLSession.read(). Return as a SocketException here. */
|
||||
throw new SocketException(e.getMessage());
|
||||
}
|
||||
|
||||
/* return number of bytes read */
|
||||
|
|
|
@ -59,6 +59,7 @@ import javax.net.ssl.SSLContext;
|
|||
import javax.net.ssl.SSLSession;
|
||||
import javax.net.ssl.SSLSessionContext;
|
||||
import javax.net.ssl.SSLSocketFactory;
|
||||
import javax.net.ssl.SSLServerSocketFactory;
|
||||
import javax.net.ssl.SSLParameters;
|
||||
import javax.net.ssl.KeyManager;
|
||||
import javax.net.ssl.KeyManagerFactory;
|
||||
|
@ -116,6 +117,8 @@ import com.wolfssl.WolfSSLException;
|
|||
public void testSessionResumptionWithTicketEnabled();
|
||||
public void testDoubleSocketClose();
|
||||
public void testSocketConnectException();
|
||||
public void testSocketCloseInterruptsWrite();
|
||||
public void testSocketCloseInterruptsRead();
|
||||
*/
|
||||
public class WolfSSLSocketTest {
|
||||
|
||||
|
@ -465,6 +468,8 @@ public class WolfSSLSocketTest {
|
|||
TestClient client = null;
|
||||
Exception srvException = null;
|
||||
Exception cliException = null;
|
||||
CountDownLatch sDoneLatch = null;
|
||||
CountDownLatch cDoneLatch = null;
|
||||
|
||||
System.out.print("\twolfjsse.enabledSupportedCurves");
|
||||
|
||||
|
@ -485,11 +490,19 @@ public class WolfSSLSocketTest {
|
|||
|
||||
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
|
||||
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
|
||||
server = new TestServer(this.ctx, ss, sArgs, 1);
|
||||
|
||||
sDoneLatch = new CountDownLatch(1);
|
||||
cDoneLatch = new CountDownLatch(1);
|
||||
|
||||
server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
|
||||
server.start();
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
|
||||
cDoneLatch);
|
||||
client.start();
|
||||
|
||||
cDoneLatch.await();
|
||||
sDoneLatch.await();
|
||||
|
||||
srvException = server.getException();
|
||||
if (srvException != null) {
|
||||
Security.setProperty("wolfjsse.enabledSupportedCurves",
|
||||
|
@ -527,11 +540,19 @@ public class WolfSSLSocketTest {
|
|||
|
||||
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
|
||||
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
|
||||
server = new TestServer(this.ctx, ss, sArgs, 1);
|
||||
|
||||
sDoneLatch = new CountDownLatch(1);
|
||||
cDoneLatch = new CountDownLatch(1);
|
||||
|
||||
server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
|
||||
server.start();
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
|
||||
cDoneLatch);
|
||||
client.start();
|
||||
|
||||
cDoneLatch.await();
|
||||
sDoneLatch.await();
|
||||
|
||||
srvException = server.getException();
|
||||
if (srvException != null) {
|
||||
Security.setProperty("wolfjsse.enabledSupportedCurves",
|
||||
|
@ -569,11 +590,19 @@ public class WolfSSLSocketTest {
|
|||
|
||||
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
|
||||
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
|
||||
server = new TestServer(this.ctx, ss, sArgs, 1);
|
||||
|
||||
sDoneLatch = new CountDownLatch(1);
|
||||
cDoneLatch = new CountDownLatch(1);
|
||||
|
||||
server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
|
||||
server.start();
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
|
||||
cDoneLatch);
|
||||
client.start();
|
||||
|
||||
cDoneLatch.await();
|
||||
sDoneLatch.await();
|
||||
|
||||
srvException = server.getException();
|
||||
if (srvException != null) {
|
||||
Security.setProperty("wolfjsse.enabledSupportedCurves",
|
||||
|
@ -600,7 +629,9 @@ public class WolfSSLSocketTest {
|
|||
}
|
||||
}
|
||||
|
||||
/* Test with invalid property entries */
|
||||
/* Test with invalid property entries.
|
||||
* Only need to start client thread, since it throws exception
|
||||
* before connecting to server. */
|
||||
{
|
||||
Security.setProperty("wolfjsse.enabledSupportedCurves",
|
||||
"badone, badtwo");
|
||||
|
@ -609,19 +640,15 @@ public class WolfSSLSocketTest {
|
|||
ss = (SSLServerSocket)ctx.getServerSocketFactory()
|
||||
.createServerSocket(0);
|
||||
|
||||
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
|
||||
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
|
||||
server = new TestServer(this.ctx, ss, sArgs, 1);
|
||||
server.start();
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
|
||||
|
||||
cDoneLatch = new CountDownLatch(1);
|
||||
|
||||
client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
|
||||
cDoneLatch);
|
||||
client.start();
|
||||
|
||||
srvException = server.getException();
|
||||
if (srvException != null) {
|
||||
Security.setProperty("wolfjsse.enabledSupportedCurves",
|
||||
originalProperty);
|
||||
throw srvException;
|
||||
}
|
||||
cDoneLatch.await();
|
||||
|
||||
cliException = client.getException();
|
||||
if (cliException != null) {
|
||||
|
@ -630,7 +657,7 @@ public class WolfSSLSocketTest {
|
|||
|
||||
try {
|
||||
client.join(1000);
|
||||
server.join(1000);
|
||||
//server.join(1000);
|
||||
|
||||
} catch (InterruptedException e) {
|
||||
System.out.println("interrupt happened");
|
||||
|
@ -656,6 +683,9 @@ public class WolfSSLSocketTest {
|
|||
@Test
|
||||
public void testClientServerThreaded() throws Exception {
|
||||
|
||||
CountDownLatch sDoneLatch = null;
|
||||
CountDownLatch cDoneLatch = null;
|
||||
|
||||
System.out.print("\tTesting basic client/server");
|
||||
|
||||
/* create new CTX */
|
||||
|
@ -668,12 +698,18 @@ public class WolfSSLSocketTest {
|
|||
TestArgs sArgs = new TestArgs(null, null, true, true, true, null);
|
||||
TestArgs cArgs = new TestArgs(null, null, false, false, true, null);
|
||||
|
||||
TestServer server = new TestServer(this.ctx, ss, sArgs, 1);
|
||||
sDoneLatch = new CountDownLatch(1);
|
||||
cDoneLatch = new CountDownLatch(1);
|
||||
|
||||
TestServer server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
|
||||
server.start();
|
||||
|
||||
TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
|
||||
TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
|
||||
cDoneLatch);
|
||||
client.start();
|
||||
|
||||
cDoneLatch.await();
|
||||
sDoneLatch.await();
|
||||
|
||||
Exception srvException = server.getException();
|
||||
if (srvException != null) {
|
||||
|
@ -700,6 +736,9 @@ public class WolfSSLSocketTest {
|
|||
public void alpnClientServerRunner(TestArgs sArgs, TestArgs cArgs,
|
||||
boolean expectingException) throws Exception {
|
||||
|
||||
CountDownLatch sDoneLatch = null;
|
||||
CountDownLatch cDoneLatch = null;
|
||||
|
||||
if (sArgs == null || cArgs == null) {
|
||||
throw new Exception("client/server TestArgs can not be null");
|
||||
}
|
||||
|
@ -710,12 +749,19 @@ public class WolfSSLSocketTest {
|
|||
SSLServerSocket ss = (SSLServerSocket)ctx.getServerSocketFactory()
|
||||
.createServerSocket(0);
|
||||
|
||||
TestServer server = new TestServer(this.ctx, ss, sArgs, 1);
|
||||
sDoneLatch = new CountDownLatch(1);
|
||||
cDoneLatch = new CountDownLatch(1);
|
||||
|
||||
TestServer server = new TestServer(this.ctx, ss, sArgs, 1, sDoneLatch);
|
||||
server.start();
|
||||
|
||||
TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs);
|
||||
TestClient client = new TestClient(this.ctx, ss.getLocalPort(), cArgs,
|
||||
cDoneLatch);
|
||||
client.start();
|
||||
|
||||
cDoneLatch.await();
|
||||
sDoneLatch.await();
|
||||
|
||||
try {
|
||||
client.join(1000);
|
||||
server.join(1000);
|
||||
|
@ -988,7 +1034,7 @@ public class WolfSSLSocketTest {
|
|||
|
||||
/* This test hangs on Android, marking TODO for later investigation. Seems to be
|
||||
* something specific to the test code, not library proper. */
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
System.out.println("\t... skipped");
|
||||
return;
|
||||
}
|
||||
|
@ -2746,6 +2792,271 @@ public class WolfSSLSocketTest {
|
|||
System.out.println("\t... passed");
|
||||
}
|
||||
|
||||
/* Test timeout set to 10000 ms (10 sec) in case inerrupt code is not
|
||||
* working as expected, we will see the timeout as a hard error that
|
||||
* this test has failed */
|
||||
@Test(timeout = 10000)
|
||||
public void testSocketCloseInterruptsWrite() throws Exception {
|
||||
|
||||
String protocol = null;
|
||||
SSLServerSocketFactory ssf = null;
|
||||
SSLServerSocket ss = null;
|
||||
SSLSocketFactory sf = null;
|
||||
boolean passed = false;
|
||||
|
||||
System.out.print("\tTesting close/write interrupt");
|
||||
|
||||
/* pipe() interrupt mechamism not implemented for Windows yet since
|
||||
* Windows does not support Unix/Linux pipe(). Re-enable this test
|
||||
* for Windows when that support has been added */
|
||||
if (WolfSSLTestFactory.isWindows()) {
|
||||
System.out.println("\t... skipped");
|
||||
return;
|
||||
}
|
||||
|
||||
if (WolfSSL.TLSv12Enabled()) {
|
||||
protocol = "TLSv1.2";
|
||||
} else if (WolfSSL.TLSv11Enabled()) {
|
||||
protocol = "TLSv1.1";
|
||||
} else if (WolfSSL.TLSv1Enabled()) {
|
||||
protocol = "TLSv1.0";
|
||||
} else {
|
||||
System.out.println("\t... skipped");
|
||||
return;
|
||||
}
|
||||
|
||||
/* create new CTX */
|
||||
this.ctx = tf.createSSLContext(protocol, ctxProvider);
|
||||
|
||||
/* create SSLServerSocket first to get ephemeral port */
|
||||
ss = (SSLServerSocket)ctx.getServerSocketFactory()
|
||||
.createServerSocket(0);
|
||||
|
||||
final SSLSocket cs = (SSLSocket)ctx.getSocketFactory().createSocket();
|
||||
cs.connect(new InetSocketAddress(ss.getLocalPort()));
|
||||
|
||||
final SSLSocket server = (SSLSocket)ss.accept();
|
||||
final CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
|
||||
ExecutorService es = Executors.newSingleThreadExecutor();
|
||||
Future<Void> serverFuture = es.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
try {
|
||||
server.startHandshake();
|
||||
|
||||
boolean doClose = closeLatch.await(90L, TimeUnit.SECONDS);
|
||||
if (!doClose) {
|
||||
/* Return without closing, latch not hit within
|
||||
* time limit */
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Sleep so write thread has a chance to do some
|
||||
* writing before interrupt */
|
||||
Thread.sleep(1000);
|
||||
cs.setSoLinger(true, 5);
|
||||
cs.close();
|
||||
|
||||
} catch (SSLException e) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail("Server thread got SSLException when not expected");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
byte[] tmpArr = new byte[1024];
|
||||
Arrays.fill(tmpArr, (byte)0xA2);
|
||||
OutputStream out = cs.getOutputStream();
|
||||
|
||||
try {
|
||||
try {
|
||||
cs.startHandshake();
|
||||
out.write(tmpArr);
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail("Exception from first out.write() when not expected");
|
||||
}
|
||||
|
||||
try {
|
||||
/* signal server thread to try and close socket */
|
||||
closeLatch.countDown();
|
||||
|
||||
/* keep writing, we should get interrupted */
|
||||
while (true) {
|
||||
out.write(tmpArr);
|
||||
}
|
||||
|
||||
} catch (SocketException e) {
|
||||
/* We expect SocketException with this message, error if
|
||||
* different than expected */
|
||||
if (!e.getMessage().contains("Socket fd closed during poll")) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail("Incorrect SocketException thrown by client");
|
||||
throw e;
|
||||
}
|
||||
|
||||
passed = true;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
es.shutdown();
|
||||
serverFuture.get();
|
||||
if (!cs.isClosed()) {
|
||||
cs.close();
|
||||
}
|
||||
if (!server.isClosed()) {
|
||||
server.close();
|
||||
}
|
||||
if (!ss.isClosed()) {
|
||||
ss.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (passed) {
|
||||
System.out.println("\t... passed");
|
||||
}
|
||||
}
|
||||
|
||||
/* Test timeout set to 10000 ms (10 sec) in case inerrupt code is not
|
||||
* working as expected, we will see the timeout as a hard error that
|
||||
* this test has failed */
|
||||
@Test(timeout = 10000)
|
||||
public void testSocketCloseInterruptsRead() throws Exception {
|
||||
|
||||
int ret = 0;
|
||||
String protocol = null;
|
||||
SSLServerSocketFactory ssf = null;
|
||||
SSLServerSocket ss = null;
|
||||
SSLSocketFactory sf = null;
|
||||
boolean passed = false;
|
||||
|
||||
System.out.print("\tTesting close/read interrupt");
|
||||
|
||||
/* pipe() interrupt mechamism not implemented for Windows yet since
|
||||
* Windows does not support Unix/Linux pipe(). Re-enable this test
|
||||
* for Windows when that support has been added */
|
||||
if (WolfSSLTestFactory.isWindows()) {
|
||||
System.out.println("\t... skipped");
|
||||
return;
|
||||
}
|
||||
|
||||
if (WolfSSL.TLSv12Enabled()) {
|
||||
protocol = "TLSv1.2";
|
||||
} else if (WolfSSL.TLSv11Enabled()) {
|
||||
protocol = "TLSv1.1";
|
||||
} else if (WolfSSL.TLSv1Enabled()) {
|
||||
protocol = "TLSv1.0";
|
||||
} else {
|
||||
System.out.println("\t... skipped");
|
||||
return;
|
||||
}
|
||||
|
||||
/* create new CTX */
|
||||
this.ctx = tf.createSSLContext(protocol, ctxProvider);
|
||||
|
||||
/* create SSLServerSocket first to get ephemeral port */
|
||||
ss = (SSLServerSocket)ctx.getServerSocketFactory()
|
||||
.createServerSocket(0);
|
||||
|
||||
final SSLSocket cs = (SSLSocket)ctx.getSocketFactory().createSocket();
|
||||
cs.connect(new InetSocketAddress(ss.getLocalPort()));
|
||||
|
||||
final SSLSocket server = (SSLSocket)ss.accept();
|
||||
final CountDownLatch closeLatch = new CountDownLatch(1);
|
||||
|
||||
ExecutorService es = Executors.newSingleThreadExecutor();
|
||||
Future<Void> serverFuture = es.submit(new Callable<Void>() {
|
||||
@Override
|
||||
public Void call() throws Exception {
|
||||
try {
|
||||
server.startHandshake();
|
||||
|
||||
boolean doClose = closeLatch.await(90L, TimeUnit.SECONDS);
|
||||
if (!doClose) {
|
||||
/* Return without closing, latch not hit within
|
||||
* time limit */
|
||||
return null;
|
||||
}
|
||||
|
||||
/* Sleep to let client thread hit read call */
|
||||
Thread.sleep(1000);
|
||||
cs.setSoLinger(true, 5);
|
||||
cs.close();
|
||||
|
||||
} catch (SSLException e) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail("Server thread got SSLException when not expected");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
byte[] tmpArr = new byte[1024];
|
||||
InputStream in = cs.getInputStream();
|
||||
|
||||
try {
|
||||
try {
|
||||
cs.startHandshake();
|
||||
}
|
||||
catch (Exception e) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail("Exception from startHandshake() when not expected");
|
||||
}
|
||||
|
||||
try {
|
||||
/* signal server thread to try and close socket */
|
||||
closeLatch.countDown();
|
||||
|
||||
while (true) {
|
||||
ret = in.read(tmpArr, 0, tmpArr.length);
|
||||
if (ret == -1) {
|
||||
/* end of stream */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} catch (SocketException e) {
|
||||
/* We expect SocketException with this message, error if
|
||||
* different than expected */
|
||||
if (!e.getMessage().contains("Socket is closed") &&
|
||||
!e.getMessage().contains("Connection already shutdown") &&
|
||||
!e.getMessage().contains("object has been freed")) {
|
||||
System.out.println("\t... failed");
|
||||
e.printStackTrace();
|
||||
fail("Incorrect SocketException thrown by client");
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
passed = true;
|
||||
}
|
||||
finally {
|
||||
es.shutdown();
|
||||
serverFuture.get();
|
||||
if (!cs.isClosed()) {
|
||||
cs.close();
|
||||
}
|
||||
if (!server.isClosed()) {
|
||||
server.close();
|
||||
}
|
||||
if (!ss.isClosed()) {
|
||||
ss.close();
|
||||
}
|
||||
}
|
||||
|
||||
if (passed) {
|
||||
System.out.println("\t... passed");
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSocketMethodsAfterClose() throws Exception {
|
||||
|
||||
|
@ -3089,13 +3400,15 @@ public class WolfSSLSocketTest {
|
|||
private int numConnections = 1;
|
||||
WolfSSLSocketTest wst;
|
||||
SSLServerSocket ss = null;
|
||||
CountDownLatch doneLatch = null;
|
||||
|
||||
public TestServer(SSLContext ctx, SSLServerSocket ss,
|
||||
TestArgs args, int numConnections) {
|
||||
TestArgs args, int numConnections, CountDownLatch doneLatch) {
|
||||
this.ctx = ctx;
|
||||
this.ss = ss;
|
||||
this.args = args;
|
||||
this.numConnections = numConnections;
|
||||
this.doneLatch = doneLatch;
|
||||
}
|
||||
|
||||
|
||||
|
@ -3175,6 +3488,8 @@ public class WolfSSLSocketTest {
|
|||
|
||||
} catch (Exception e) {
|
||||
this.exception = e;
|
||||
} finally {
|
||||
this.doneLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3202,11 +3517,14 @@ public class WolfSSLSocketTest {
|
|||
private Exception exception = null;
|
||||
private TestArgs args = null;
|
||||
WolfSSLSocketTest wst;
|
||||
CountDownLatch doneLatch = null;
|
||||
|
||||
public TestClient(SSLContext ctx, int port, TestArgs args) {
|
||||
public TestClient(SSLContext ctx, int port, TestArgs args,
|
||||
CountDownLatch doneLatch) {
|
||||
this.ctx = ctx;
|
||||
this.srvPort = port;
|
||||
this.args = args;
|
||||
this.doneLatch = doneLatch;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -3271,6 +3589,8 @@ public class WolfSSLSocketTest {
|
|||
|
||||
} catch (Exception e) {
|
||||
this.exception = e;
|
||||
} finally {
|
||||
this.doneLatch.countDown();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1052,13 +1052,24 @@ class WolfSSLTestFactory {
|
|||
* Test if the env is Android
|
||||
* @return true if is Android system
|
||||
*/
|
||||
protected boolean isAndroid() {
|
||||
protected static boolean isAndroid() {
|
||||
if (System.getProperty("java.runtime.name").contains("Android")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if the env is Windows.
|
||||
* @return true if Windows, otherwise false
|
||||
*/
|
||||
protected static boolean isWindows() {
|
||||
if (System.getProperty("os.name").startsWith("Windows")) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if Security property contains a specific value.
|
||||
*
|
||||
|
|
|
@ -121,7 +121,7 @@ public class WolfSSLTrustX509Test {
|
|||
|
||||
System.out.print("\tTesting parse all.jks");
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
/* @TODO finding that BKS has different order of certs */
|
||||
pass("\t... skipped");
|
||||
return;
|
||||
|
@ -186,7 +186,7 @@ public class WolfSSLTrustX509Test {
|
|||
|
||||
System.out.print("\tTesting use before init()");
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
/* @TODO finding that BKS has different order of certs */
|
||||
pass("\t... skipped");
|
||||
return;
|
||||
|
@ -242,7 +242,7 @@ public class WolfSSLTrustX509Test {
|
|||
|
||||
System.out.print("\tTesting parsing server.jks");
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
/* @TODO finding that BKS has different order of certs */
|
||||
pass("\t... skipped");
|
||||
return;
|
||||
|
@ -312,7 +312,7 @@ public class WolfSSLTrustX509Test {
|
|||
|
||||
System.out.print("\tTesting parse all_mixed.jks");
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
/* @TODO finding that BKS has different order of certs */
|
||||
pass("\t... skipped");
|
||||
return;
|
||||
|
@ -570,7 +570,7 @@ public class WolfSSLTrustX509Test {
|
|||
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
|
||||
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
rsaServerCert = "/sdcard/" + rsaServerCert;
|
||||
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
|
||||
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
|
||||
|
@ -697,7 +697,7 @@ public class WolfSSLTrustX509Test {
|
|||
"examples/certs/intermediate/ca-int-cert.pem";
|
||||
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
rsaServerCert = "/sdcard/" + rsaServerCert;
|
||||
rsaInt1CertWrong = "/sdcard/" + rsaInt1CertWrong;
|
||||
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
|
||||
|
@ -825,7 +825,7 @@ public class WolfSSLTrustX509Test {
|
|||
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
|
||||
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
rsaServerCert = "/sdcard/" + rsaServerCert;
|
||||
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
|
||||
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
|
||||
|
@ -948,7 +948,7 @@ public class WolfSSLTrustX509Test {
|
|||
"examples/certs/intermediate/server-int-ecc-cert.pem";
|
||||
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
rsaServerCert = "/sdcard/" + rsaServerCert;
|
||||
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
|
||||
|
||||
|
@ -1054,7 +1054,7 @@ public class WolfSSLTrustX509Test {
|
|||
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
|
||||
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
rsaServerCert = "/sdcard/" + rsaServerCert;
|
||||
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
|
||||
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
|
||||
|
@ -1180,7 +1180,7 @@ public class WolfSSLTrustX509Test {
|
|||
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
|
||||
String eccInt2Cert = "examples/certs/intermediate/ca-int2-ecc-cert.pem";
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
rsaServerCert = "/sdcard/" + rsaServerCert;
|
||||
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
|
||||
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
|
||||
|
@ -1340,7 +1340,7 @@ public class WolfSSLTrustX509Test {
|
|||
String eccInt1Cert = "examples/certs/intermediate/ca-int-ecc-cert.pem";
|
||||
String eccRootCert = "examples/certs/ca-ecc-cert.pem";
|
||||
|
||||
if (tf.isAndroid()) {
|
||||
if (WolfSSLTestFactory.isAndroid()) {
|
||||
rsaServerCert = "/sdcard/" + rsaServerCert;
|
||||
rsaInt1Cert = "/sdcard/" + rsaInt1Cert;
|
||||
rsaInt2Cert = "/sdcard/" + rsaInt2Cert;
|
||||
|
|
|
@ -363,7 +363,7 @@ public class WolfSSLX509Test {
|
|||
break;
|
||||
}
|
||||
}
|
||||
if (sigProvider == null || tf.isAndroid()) {
|
||||
if (sigProvider == null || WolfSSLTestFactory.isAndroid()) {
|
||||
pass("\t\t\t... skipped");
|
||||
return;
|
||||
}
|
||||
|
@ -511,7 +511,7 @@ public class WolfSSLX509Test {
|
|||
}
|
||||
|
||||
/* Android KeyStore formats x509 getName() differently than peer getName() */
|
||||
if (!tf.isAndroid()) {
|
||||
if (!WolfSSLTestFactory.isAndroid()) {
|
||||
if (!x509.getSubjectDN().getName().equals(
|
||||
peer.getSubjectDN().getName())) {
|
||||
error("\t\t... failed");
|
||||
|
|
Loading…
Reference in New Issue