Skip to content

Commit

Permalink
Merge pull request #230 from cconlon/deadlockFixes
Browse files Browse the repository at this point in the history
JSSE: fix deadlock issues between SSLSocket close() and OutputStream write()
  • Loading branch information
JacobBarthelmeh authored Nov 6, 2024
2 parents 30e4042 + fe40fe7 commit fa2a5af
Showing 1 changed file with 81 additions and 63 deletions.
144 changes: 81 additions & 63 deletions src/java/com/wolfssl/provider/jsse/WolfSSLSocket.java
Original file line number Diff line number Diff line change
Expand Up @@ -1937,18 +1937,16 @@ public synchronized void close() throws IOException {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"thread got ioLock (shutdown)");

synchronized (handshakeLock) {
if (this.getUseClientMode() == true &&
this.handshakeComplete == true) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"saving WOLFSSL_SESSION into cache");
EngineHelper.saveSession();
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"not saving WOLFSSL_SESSION into cache, " +
"not client or handshake not complete");
}
if ((this.getUseClientMode() == true) &&
(handshakeFinished == true)) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"saving WOLFSSL_SESSION into cache");
EngineHelper.saveSession();
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"not saving WOLFSSL_SESSION into cache, " +
"not client or handshake not complete");
}

try {
Expand Down Expand Up @@ -2001,26 +1999,32 @@ public synchronized void close() throws IOException {
this.EngineHelper.clearObjectState();
this.EngineHelper = null;

/* Release Input/OutputStream objects. Do not
* close WolfSSLSocket inside stream close,
* since we handle that next below and do
* differently depending on if autoClose has been
* set or not. */
if (this.inStream != null) {
this.inStream.close(false);
this.inStream = null;
}
if (this.outStream != null) {
this.outStream.close(false);
this.outStream = null;
}
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"thread exiting handshakeLock (shutdown)");

} /* handshakeLock */

WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"thread exiting ioLock (shutdown)");

} /* ioLock */

/* Release Input/OutputStream objects. Do not close
* WolfSSLSocket inside stream close, since we handle that
* next below and do differently depending on if autoClose
* has been set or not. */
if (this.inStream != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"close(), closing InputStream");
this.inStream.close(false);
this.inStream = null;
}
if (this.outStream != null) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"close(), closing OutputStream");
this.outStream.close(false);
this.outStream = null;
}
}
}

Expand Down Expand Up @@ -2457,27 +2461,28 @@ protected void close(boolean closeSocket) throws IOException {

if (isClosing.compareAndSet(false, true)) {

synchronized (this) {
if (closeSocket) {
if (this.socket == null || this.isClosed) {
return;
}

if (this.socket.isClosed()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (input) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (input) closed: " + this.socket);
}
if (closeSocket) {
if (this.socket == null || this.isClosed) {
return;
}

this.socket = null;
this.ssl = null;
this.isClosed = true;
if (this.socket.isClosed()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (input) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (input) closed: " + this.socket);
}
}

this.socket = null;
this.ssl = null;
this.isClosed = true;

/* Reset "is closing" state to false, now closed */
isClosing.set(false);
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
Expand Down Expand Up @@ -2534,6 +2539,12 @@ public synchronized int read(byte[] b, int off, int len)
throw new NullPointerException("Input array is null");
}

/* check if socket is closing */
if (isClosing.get()) {
throw new SocketException(
"InputStream in process of being closed");
}

/* check if socket is closed */
if (this.isClosed || socket == null || socket.isClosed()) {
throw new SocketException("Socket is closed");
Expand Down Expand Up @@ -2670,27 +2681,28 @@ protected void close(boolean closeSocket) throws IOException {

if (isClosing.compareAndSet(false, true)) {

synchronized (this) {
if (closeSocket) {
if (this.socket == null || this.isClosed) {
return;
}

if (this.socket.isClosed()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (output) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (output) closed: " + this.socket);
}
if (closeSocket) {
if (this.socket == null || this.isClosed) {
return;
}

this.socket = null;
this.ssl = null;
this.isClosed = true;
if (this.socket.isClosed()) {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (output) already closed");
}
else {
this.socket.close();
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
"socket (output) closed: " + this.socket);
}
}

this.socket = null;
this.ssl = null;
this.isClosed = true;

/* Reset "is closing" state to false, now closed */
isClosing.set(false);
}
else {
WolfSSLDebug.log(getClass(), WolfSSLDebug.INFO,
Expand All @@ -2707,14 +2719,14 @@ public void close() throws IOException {
this.close(true);
}

public synchronized void write(int b) throws IOException {
public void write(int b) throws IOException {
byte[] data = new byte[1];
data[0] = (byte)(b & 0xFF);

this.write(data, 0, 1);
}

public synchronized void write(byte[] b) throws IOException {
public void write(byte[] b) throws IOException {
this.write(b, 0, b.length);
}

Expand All @@ -2727,6 +2739,12 @@ public synchronized void write(byte[] b, int off, int len)
throw new NullPointerException("Input array is null");
}

/* check if socket is closing */
if (isClosing.get()) {
throw new SocketException(
"OutputStream in process of being closed");
}

/* check if socket is closed */
if (this.isClosed || socket == null || socket.isClosed()) {
throw new SocketException("Socket is closed");
Expand Down

0 comments on commit fa2a5af

Please sign in to comment.