6447412: Issue with socket.close() for ssl sockets when poweroff on other system
Support SSL sockets SOLINGER Reviewed-by: chegar
This commit is contained in:
parent
e61d136dd9
commit
04886b6f44
@ -617,7 +617,8 @@ abstract class Handshaker {
|
||||
r.write(1); // single byte of data
|
||||
|
||||
if (conn != null) {
|
||||
synchronized (conn.writeLock) {
|
||||
conn.writeLock.lock();
|
||||
try {
|
||||
conn.writeRecord(r);
|
||||
conn.changeWriteCiphers();
|
||||
if (debug != null && Debug.isOn("handshake")) {
|
||||
@ -625,6 +626,8 @@ abstract class Handshaker {
|
||||
}
|
||||
mesg.write(output);
|
||||
output.flush();
|
||||
} finally {
|
||||
conn.writeLock.unlock();
|
||||
}
|
||||
} else {
|
||||
synchronized (engine.writeLock) {
|
||||
|
@ -174,6 +174,18 @@ class OutputRecord extends ByteArrayOutputStream implements Record {
|
||||
return count == headerSize;
|
||||
}
|
||||
|
||||
/*
|
||||
* Return true if the record is of a given alert.
|
||||
*/
|
||||
boolean isAlert(byte description) {
|
||||
// An alert is defined with a two bytes struct,
|
||||
// {byte level, byte description}, following after the header bytes.
|
||||
if (count > (headerSize + 1) && contentType == ct_alert) {
|
||||
return buf[headerSize + 1] == description;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute the MAC and append it to this record. In case we
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 1996-2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* Copyright 1996-2008 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
@ -33,6 +33,8 @@ import java.security.AccessController;
|
||||
import java.security.AccessControlContext;
|
||||
import java.security.PrivilegedAction;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.concurrent.locks.ReentrantLock;
|
||||
|
||||
import javax.crypto.BadPaddingException;
|
||||
|
||||
@ -274,7 +276,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* from the peer are handled properly.
|
||||
*/
|
||||
private Object handshakeLock;
|
||||
Object writeLock;
|
||||
ReentrantLock writeLock;
|
||||
private Object readLock;
|
||||
|
||||
private InputRecord inrec;
|
||||
@ -314,7 +316,6 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
private HashMap<HandshakeCompletedListener, AccessControlContext>
|
||||
handshakeListeners;
|
||||
|
||||
|
||||
/*
|
||||
* Reuse the same internal input/output streams.
|
||||
*/
|
||||
@ -526,7 +527,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
enabledCipherSuites = CipherSuiteList.getDefault();
|
||||
enabledProtocols = ProtocolList.getDefault();
|
||||
handshakeLock = new Object();
|
||||
writeLock = new Object();
|
||||
writeLock = new ReentrantLock();
|
||||
readLock = new Object();
|
||||
inrec = null;
|
||||
|
||||
@ -677,16 +678,81 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
// implementations are fragile and don't like to see empty
|
||||
// records, so this also increases robustness.
|
||||
//
|
||||
synchronized (writeLock) {
|
||||
if (!r.isEmpty()) {
|
||||
// r.compress(c);
|
||||
r.addMAC(writeMAC);
|
||||
r.encrypt(writeCipher);
|
||||
r.write(sockOutput);
|
||||
if (!r.isEmpty()) {
|
||||
|
||||
// If the record is a close notify alert, we need to honor
|
||||
// socket option SO_LINGER. Note that we will try to send
|
||||
// the close notify even if the SO_LINGER set to zero.
|
||||
if (r.isAlert(Alerts.alert_close_notify) && getSoLinger() >= 0) {
|
||||
|
||||
// keep and clear the current thread interruption status.
|
||||
boolean interrupted = Thread.interrupted();
|
||||
try {
|
||||
if (writeLock.tryLock(getSoLinger(), TimeUnit.SECONDS)) {
|
||||
try {
|
||||
writeRecordInternal(r);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
} else {
|
||||
SSLException ssle = new SSLException(
|
||||
"SO_LINGER timeout," +
|
||||
" close_notify message cannot be sent.");
|
||||
|
||||
|
||||
// For layered, non-autoclose sockets, we are not
|
||||
// able to bring them into a usable state, so we
|
||||
// treat it as fatal error.
|
||||
if (self != this && !autoClose) {
|
||||
// Note that the alert description is
|
||||
// specified as -1, so no message will be send
|
||||
// to peer anymore.
|
||||
fatal((byte)(-1), ssle);
|
||||
} else if ((debug != null) && Debug.isOn("ssl")) {
|
||||
System.out.println(threadName() +
|
||||
", received Exception: " + ssle);
|
||||
}
|
||||
|
||||
// RFC2246 requires that the session becomes
|
||||
// unresumable if any connection is terminated
|
||||
// without proper close_notify messages with
|
||||
// level equal to warning.
|
||||
//
|
||||
// RFC4346 no longer requires that a session not be
|
||||
// resumed if failure to properly close a connection.
|
||||
//
|
||||
// We choose to make the session unresumable if
|
||||
// failed to send the close_notify message.
|
||||
//
|
||||
sess.invalidate();
|
||||
}
|
||||
} catch (InterruptedException ie) {
|
||||
// keep interrupted status
|
||||
interrupted = true;
|
||||
}
|
||||
|
||||
// restore the interrupted status
|
||||
if (interrupted) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
} else {
|
||||
writeLock.lock();
|
||||
try {
|
||||
writeRecordInternal(r);
|
||||
} finally {
|
||||
writeLock.unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void writeRecordInternal(OutputRecord r) throws IOException {
|
||||
// r.compress(c);
|
||||
r.addMAC(writeMAC);
|
||||
r.encrypt(writeCipher);
|
||||
r.write(sockOutput);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Read an application data record. Alerts and handshake
|
||||
@ -1533,7 +1599,11 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
if (oldState == cs_HANDSHAKE) {
|
||||
sockInput.skip(sockInput.available());
|
||||
}
|
||||
sendAlert(Alerts.alert_fatal, description);
|
||||
|
||||
// If the description equals -1, the alert won't be sent to peer.
|
||||
if (description != -1) {
|
||||
sendAlert(Alerts.alert_fatal, description);
|
||||
}
|
||||
if (cause instanceof SSLException) { // only true if != null
|
||||
closeReason = (SSLException)cause;
|
||||
} else {
|
||||
@ -1614,7 +1684,7 @@ final public class SSLSocketImpl extends BaseSSLSocketImpl {
|
||||
* Emit alerts. Caller must have synchronized with "this".
|
||||
*/
|
||||
private void sendAlert(byte level, byte description) {
|
||||
if (connectionState >= cs_CLOSED) {
|
||||
if (connectionState >= cs_SENT_CLOSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,116 @@
|
||||
/*
|
||||
* Copyright 2007 Sun Microsystems, Inc. All Rights Reserved.
|
||||
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
||||
*
|
||||
* This code is free software; you can redistribute it and/or modify it
|
||||
* under the terms of the GNU General Public License version 2 only, as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* This code is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
||||
* version 2 for more details (a copy is included in the LICENSE file that
|
||||
* accompanied this code).
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License version
|
||||
* 2 along with this work; if not, write to the Free Software Foundation,
|
||||
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
|
||||
* CA 95054 USA or visit www.sun.com if you need additional information or
|
||||
* have any questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @bug 6447412
|
||||
* @summary Issue with socket.close() for ssl sockets when poweroff on
|
||||
* other system
|
||||
*/
|
||||
|
||||
import javax.net.ssl.*;
|
||||
import java.io.*;
|
||||
|
||||
public class AsyncSSLSocketClose implements Runnable
|
||||
{
|
||||
SSLSocket socket;
|
||||
SSLServerSocket ss;
|
||||
|
||||
// Where do we find the keystores?
|
||||
static String pathToStores = "../../../../../../../etc";
|
||||
static String keyStoreFile = "keystore";
|
||||
static String trustStoreFile = "truststore";
|
||||
static String passwd = "passphrase";
|
||||
|
||||
public static void main(String[] args) {
|
||||
String keyFilename =
|
||||
System.getProperty("test.src", "./") + "/" + pathToStores +
|
||||
"/" + keyStoreFile;
|
||||
String trustFilename =
|
||||
System.getProperty("test.src", "./") + "/" + pathToStores +
|
||||
"/" + trustStoreFile;
|
||||
|
||||
System.setProperty("javax.net.ssl.keyStore", keyFilename);
|
||||
System.setProperty("javax.net.ssl.keyStorePassword", passwd);
|
||||
System.setProperty("javax.net.ssl.trustStore", trustFilename);
|
||||
System.setProperty("javax.net.ssl.trustStorePassword", passwd);
|
||||
|
||||
new AsyncSSLSocketClose();
|
||||
}
|
||||
|
||||
public AsyncSSLSocketClose() {
|
||||
try {
|
||||
SSLServerSocketFactory sslssf =
|
||||
(SSLServerSocketFactory)SSLServerSocketFactory.getDefault();
|
||||
ss = (SSLServerSocket) sslssf.createServerSocket(0);
|
||||
|
||||
SSLSocketFactory sslsf =
|
||||
(SSLSocketFactory)SSLSocketFactory.getDefault();
|
||||
socket = (SSLSocket)sslsf.createSocket("localhost",
|
||||
ss.getLocalPort());
|
||||
SSLSocket serverSoc = (SSLSocket) ss.accept();
|
||||
ss.close();
|
||||
|
||||
(new Thread(this)).start();
|
||||
serverSoc.startHandshake();
|
||||
|
||||
try {
|
||||
Thread.sleep(5000);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
socket.setSoLinger(true, 10);
|
||||
System.out.println("Calling Socket.close");
|
||||
socket.close();
|
||||
System.out.println("ssl socket get closed");
|
||||
System.out.flush();
|
||||
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// block in write
|
||||
public void run() {
|
||||
try {
|
||||
byte[] ba = new byte[1024];
|
||||
for (int i=0; i<ba.length; i++)
|
||||
ba[i] = 0x7A;
|
||||
|
||||
OutputStream os = socket.getOutputStream();
|
||||
int count = 0;
|
||||
while (true) {
|
||||
count += ba.length;
|
||||
System.out.println(count + " bytes to be written");
|
||||
os.write(ba);
|
||||
System.out.println(count + " bytes written");
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user