下面列出了怎么用javax.net.ssl.SSLEngineResult.Status的API类实例代码及写法,或者点击链接到github查看源代码。
private void checkResult(SSLEngineResult result, boolean wrap)
throws SSLException {
handshakeStatus = result.getHandshakeStatus();
resultStatus = result.getStatus();
if (resultStatus != Status.OK &&
(wrap || resultStatus != Status.BUFFER_UNDERFLOW)) {
throw new SSLException(
sm.getString("asyncChannelWrapperSecure.check.notOk", resultStatus));
}
if (wrap && result.bytesConsumed() != 0) {
throw new SSLException(sm.getString("asyncChannelWrapperSecure.check.wrap"));
}
if (!wrap && result.bytesProduced() != 0) {
throw new SSLException(sm.getString("asyncChannelWrapperSecure.check.unwrap"));
}
}
/**
* Perform handshake unwrap
* @return the result
* @throws IOException An IO error occurred
*/
protected SSLEngineResult handshakeUnwrap() throws IOException {
SSLEngineResult result;
boolean cont = false;
//loop while we can perform pure SSLEngine data
do {
//prepare the buffer with the incoming data
netInBuffer.flip();
//call unwrap
getBufHandler().configureReadBufferForWrite();
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
handshakeStatus = result.getHandshakeStatus();
if (result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
//execute tasks if we need to
handshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
} while (cont);
return result;
}
public SSLSocketChannel2( SocketChannel channel , SSLEngine sslEngine , ExecutorService exec , SelectionKey key ) throws IOException {
if( channel == null || sslEngine == null || exec == null )
throw new IllegalArgumentException( "parameter must not be null" );
this.socketChannel = channel;
this.sslEngine = sslEngine;
this.exec = exec;
readEngineResult = writeEngineResult = new SSLEngineResult( Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0 ); // init to prevent NPEs
tasks = new ArrayList<Future<?>>( 3 );
if( key != null ) {
key.interestOps( key.interestOps() | SelectionKey.OP_WRITE );
this.selectionKey = key;
}
createBuffers( sslEngine.getSession() );
// kick off handshake
socketChannel.write( wrap( emptybuffer ) );// initializes res
processHandshake();
}
public SSLSocketChannel2(SocketChannel channel, SSLEngine sslEngine, ExecutorService exec,
SelectionKey key)
throws IOException {
if (channel == null || sslEngine == null || exec == null) {
throw new IllegalArgumentException("parameter must not be null");
}
this.socketChannel = channel;
this.sslEngine = sslEngine;
this.exec = exec;
readEngineResult = writeEngineResult =
new SSLEngineResult(Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0,
0); // init to prevent NPEs
tasks = new ArrayList<Future<?>>(3);
if (key != null) {
key.interestOps(key.interestOps() | SelectionKey.OP_WRITE);
this.selectionKey = key;
}
createBuffers(sslEngine.getSession());
// kick off handshake
socketChannel.write(wrap(emptybuffer));// initializes res
processHandshake();
}
/**
* {@link #read(ByteBuffer)} may not be to leave all buffers(inData, inCrypt)
**/
private int readRemaining( ByteBuffer dst ) throws SSLException {
if( inData.hasRemaining() ) {
return transfereTo( inData, dst );
}
if( !inData.hasRemaining() )
inData.clear();
// test if some bytes left from last read (e.g. BUFFER_UNDERFLOW)
if( inCrypt.hasRemaining() ) {
unwrap();
int amount = transfereTo( inData, dst );
if (readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) {
return -1;
}
if( amount > 0 )
return amount;
}
return 0;
}
@Override
public int write(ByteBuffer src) throws IOException {
if (!isHandShakeComplete()) {
processHandshake();
return 0;
}
// assert ( bufferallocations > 1 ); //see #190
//if( bufferallocations <= 1 ) {
// createBuffers( sslEngine.getSession() );
//}
int num = socketChannel.write(wrap(src));
if (writeEngineResult.getStatus() == Status.CLOSED) {
throw new EOFException("Connection is closed");
}
return num;
}
/**
* {@link #read(ByteBuffer)} may not be to leave all buffers(inData, inCrypt)
**/
private int readRemaining(ByteBuffer dst) throws SSLException {
if (inData.hasRemaining()) {
return transfereTo(inData, dst);
}
if (!inData.hasRemaining()) {
inData.clear();
}
// test if some bytes left from last read (e.g. BUFFER_UNDERFLOW)
if (inCrypt.hasRemaining()) {
unwrap();
int amount = transfereTo(inData, dst);
if (readEngineResult.getStatus() == Status.CLOSED) {
return -1;
}
if (amount > 0) {
return amount;
}
}
return 0;
}
public SSLStreams.WrapperResult sendData(ByteBuffer src) throws IOException {
SSLStreams.WrapperResult r = null;
while(src.remaining() > 0) {
r = this.wrapper.wrapAndSend(src);
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
this.doClosure();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING) {
this.doHandshake(hs_status);
}
}
return r;
}
/**
* {@link #read(ByteBuffer)} may not be to leave all buffers(inData, inCrypt)
**/
private int readRemaining( ByteBuffer dst ) throws SSLException {
if( inData.hasRemaining() ) {
return transfereTo( inData, dst );
}
if( !inData.hasRemaining() )
inData.clear();
// test if some bytes left from last read (e.g. BUFFER_UNDERFLOW)
if( inCrypt.hasRemaining() ) {
unwrap();
int amount = transfereTo( inData, dst );
if (readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) {
return -1;
}
if( amount > 0 )
return amount;
}
return 0;
}
public void write(byte[] b, int off, int len) throws IOException {
if (this.closed) {
throw new IOException("output stream is closed");
} else {
while(len > 0) {
int l = len > this.buf.capacity() ? this.buf.capacity() : len;
this.buf.clear();
this.buf.put(b, off, l);
len -= l;
off += l;
this.buf.flip();
SSLStreams.WrapperResult r = SSLStreams.this.sendData(this.buf);
if (r.result.getStatus() == Status.CLOSED) {
this.closed = true;
if (len > 0) {
throw new IOException("output stream is closed");
}
}
}
}
}
public SSLStreams.WrapperResult sendData(ByteBuffer src) throws IOException {
SSLStreams.WrapperResult r = null;
while(src.remaining() > 0) {
r = this.wrapper.wrapAndSend(src);
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
this.doClosure();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING) {
this.doHandshake(hs_status);
}
}
return r;
}
public void write(byte[] b, int off, int len) throws IOException {
if (this.closed) {
throw new IOException("output stream is closed");
} else {
while(len > 0) {
int l = len > this.buf.capacity() ? this.buf.capacity() : len;
this.buf.clear();
this.buf.put(b, off, l);
len -= l;
off += l;
this.buf.flip();
SSLStreams.WrapperResult r = SSLStreams.this.sendData(this.buf);
if (r.result.getStatus() == Status.CLOSED) {
this.closed = true;
if (len > 0) {
throw new IOException("output stream is closed");
}
}
}
}
}
public SSLStreams.WrapperResult sendData(ByteBuffer src) throws IOException {
SSLStreams.WrapperResult r = null;
while(src.remaining() > 0) {
r = this.wrapper.wrapAndSend(src);
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
this.doClosure();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED && hs_status != HandshakeStatus.NOT_HANDSHAKING) {
this.doHandshake(hs_status);
}
}
return r;
}
void doClosure() throws IOException {
try {
this.handshaking.lock();
ByteBuffer tmp = this.allocate(SSLStreams.BufType.APPLICATION);
SSLStreams.WrapperResult r;
do {
tmp.clear();
tmp.flip();
r = this.wrapper.wrapAndSendX(tmp, true);
} while(r.result.getStatus() != Status.CLOSED);
} finally {
this.handshaking.unlock();
}
}
public void write(byte[] b, int off, int len) throws IOException {
if (this.closed) {
throw new IOException("output stream is closed");
} else {
while(len > 0) {
int l = len > this.buf.capacity() ? this.buf.capacity() : len;
this.buf.clear();
this.buf.put(b, off, l);
len -= l;
off += l;
this.buf.flip();
SSLStreams.WrapperResult r = SSLStreams.this.sendData(this.buf);
if (r.result.getStatus() == Status.CLOSED) {
this.closed = true;
if (len > 0) {
throw new IOException("output stream is closed");
}
}
}
}
}
void doClosure() throws IOException {
try {
this.handshaking.lock();
ByteBuffer tmp = this.allocate(SSLStreams.BufType.APPLICATION);
SSLStreams.WrapperResult r;
do {
tmp.clear();
tmp.flip();
r = this.wrapper.wrapAndSendX(tmp, true);
} while(r.result.getStatus() != Status.CLOSED);
} finally {
this.handshaking.unlock();
}
}
public void write(byte[] b, int off, int len) throws IOException {
if (this.closed) {
throw new IOException("output stream is closed");
} else {
while(len > 0) {
int l = len > this.buf.capacity() ? this.buf.capacity() : len;
this.buf.clear();
this.buf.put(b, off, l);
len -= l;
off += l;
this.buf.flip();
SSLStreams.WrapperResult r = SSLStreams.this.sendData(this.buf);
if (r.result.getStatus() == Status.CLOSED) {
this.closed = true;
if (len > 0) {
throw new IOException("output stream is closed");
}
}
}
}
}
/**
* Returns the current status for this TLSHandler.
*
* @return the current TLSStatus
*/
public TLSStatus getStatus() {
if (tlsEngineResult != null && tlsEngineResult.getStatus() == Status.BUFFER_UNDERFLOW) {
return TLSStatus.UNDERFLOW;
} else {
if (tlsEngineResult != null && tlsEngineResult.getStatus() == Status.CLOSED) {
return TLSStatus.CLOSED;
} else {
switch (tlsEngine.getHandshakeStatus()) {
case NEED_WRAP:
return TLSStatus.NEED_WRITE;
case NEED_UNWRAP:
return TLSStatus.NEED_READ;
default:
return TLSStatus.OK;
}
}
}
}
private Status encryptAndWriteFully(final BufferStateManager src) throws IOException {
SSLEngineResult result = null;
final ByteBuffer buff = src.prepareForRead(0);
final ByteBuffer outBuff = streamOutManager.prepareForWrite(engine.getSession().getApplicationBufferSize());
logger.trace("{} Encrypting {} bytes", this, buff.remaining());
while (buff.remaining() > 0) {
result = engine.wrap(buff, outBuff);
if (result.getStatus() == Status.OK) {
final ByteBuffer readableOutBuff = streamOutManager.prepareForRead(0);
writeFully(readableOutBuff);
streamOutManager.clear();
} else {
return result.getStatus();
}
}
return result.getStatus();
}
public SSLSocketChannel2( SocketChannel channel , SSLEngine sslEngine , ExecutorService exec , SelectionKey key ) throws IOException {
if( channel == null || sslEngine == null || exec == null )
throw new IllegalArgumentException( "parameter must not be null" );
this.socketChannel = channel;
this.sslEngine = sslEngine;
this.exec = exec;
readEngineResult = writeEngineResult = new SSLEngineResult( Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0 ); // init to prevent NPEs
tasks = new ArrayList<Future<?>>( 3 );
if( key != null ) {
key.interestOps( key.interestOps() | SelectionKey.OP_WRITE );
this.selectionKey = key;
}
createBuffers( sslEngine.getSession() );
// kick off handshake
socketChannel.write( wrap( emptybuffer ) );// initializes res
processHandshake();
}
public int write( ByteBuffer src ) throws IOException {
if( !isHandShakeComplete() ) {
processHandshake();
return 0;
}
// assert ( bufferallocations > 1 ); //see #190
//if( bufferallocations <= 1 ) {
// createBuffers( sslEngine.getSession() );
//}
int num = socketChannel.write( wrap( src ) );
if (writeEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) {
throw new EOFException("Connection is closed");
}
return num;
}
private void checkResult(SSLEngineResult result, boolean wrap)
throws SSLException {
handshakeStatus = result.getHandshakeStatus();
resultStatus = result.getStatus();
if (resultStatus != Status.OK &&
(wrap || resultStatus != Status.BUFFER_UNDERFLOW)) {
throw new SSLException("TODO");
}
if (wrap && result.bytesConsumed() != 0) {
throw new SSLException("TODO");
}
if (!wrap && result.bytesProduced() != 0) {
throw new SSLException("TODO");
}
}
/**
* Sends a SSL close message, will not physically close the connection here.<br>
* To close the connection, you could do something like
* <pre><code>
* close();
* while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
* if ( isOpen() ) close(true); //forces a close if you timed out
* </code></pre>
* @throws IOException if an I/O error occurs
* @throws IOException if there is data on the outgoing network buffer and we are unable to flush it
* TODO Implement this java.io.Closeable method
*/
@Override
public void close() throws IOException {
if (closing) return;
closing = true;
sslEngine.closeOutbound();
if (!flush(netOutBuffer)) {
throw new IOException("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead");
}
//prep the buffer for the close message
netOutBuffer.clear();
//perform the close, since we called sslEngine.closeOutbound
SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
//we should be in a close state
if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
throw new IOException("Invalid close state, will not send network data.");
}
//prepare the buffer for writing
netOutBuffer.flip();
//if there is data to be written
flush(netOutBuffer);
//is the channel closed?
closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
}
/**
* read data thru the engine into the given ByteBuffer. If the
* given buffer was not large enough, a new one is allocated
* and returned. This call handles handshaking automatically.
* Caller should check if engine has been closed.
*/
WrapperResult recvData (ByteBuffer dst) throws IOException {
/* we wait until some user data arrives */
int mark = dst.position();
WrapperResult r = null;
int pos = dst.position();
while (dst.position() == pos) {
r = wrapper.recvAndUnwrap (dst);
dst = (r.buf != dst) ? r.buf: dst;
Status status = r.result.getStatus();
if (status == Status.CLOSED) {
doClosure ();
return r;
}
HandshakeStatus hs_status = r.result.getHandshakeStatus();
if (hs_status != HandshakeStatus.FINISHED &&
hs_status != HandshakeStatus.NOT_HANDSHAKING)
{
doHandshake (hs_status);
}
}
Utils.flipToMark(dst, mark);
return r;
}
/**
* Sends a SSL close message, will not physically close the connection here.<br>
* To close the connection, you could do something like
* <pre><code>
* close();
* while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
* if ( isOpen() ) close(true); //forces a close if you timed out
* </code></pre>
* @throws IOException if an I/O error occurs
* @throws IOException if there is data on the outgoing network buffer and we are unable to flush it
* TODO Implement this java.io.Closeable method
*/
@Override
public void close() throws IOException {
if (closing) return;
closing = true;
sslEngine.closeOutbound();
if (!flush(netOutBuffer)) {
throw new IOException("Remaining data in the network buffer, can't send SSL close message, force a close with close(true) instead");
}
//prep the buffer for the close message
netOutBuffer.clear();
//perform the close, since we called sslEngine.closeOutbound
SSLEngineResult handshake = sslEngine.wrap(getEmptyBuf(), netOutBuffer);
//we should be in a close state
if (handshake.getStatus() != SSLEngineResult.Status.CLOSED) {
throw new IOException("Invalid close state, will not send network data.");
}
//prepare the buffer for writing
netOutBuffer.flip();
//if there is data to be written
flush(netOutBuffer);
//is the channel closed?
closed = (!netOutBuffer.hasRemaining() && (handshake.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));
}
public SSLSocketChannel2( SocketChannel channel , SSLEngine sslEngine , ExecutorService exec , SelectionKey key ) throws IOException {
if( channel == null || sslEngine == null || exec == null )
throw new IllegalArgumentException( "parameter must not be null" );
this.socketChannel = channel;
this.sslEngine = sslEngine;
this.exec = exec;
readEngineResult = writeEngineResult = new SSLEngineResult( Status.BUFFER_UNDERFLOW, sslEngine.getHandshakeStatus(), 0, 0 ); // init to prevent NPEs
tasks = new ArrayList<Future<?>>( 3 );
if( key != null ) {
key.interestOps( key.interestOps() | SelectionKey.OP_WRITE );
this.selectionKey = key;
}
createBuffers( sslEngine.getSession() );
// kick off handshake
socketChannel.write( wrap( emptybuffer ) );// initializes res
processHandshake();
}
/**
* performs the unwrap operation by unwrapping from {@link #inCrypt} to {@link #inData}
**/
private synchronized ByteBuffer unwrap() throws SSLException {
int rem;
//There are some ssl test suites, which get around the selector.select() call, which cause an infinite unwrap and 100% cpu usage (see #459 and #458)
if(readEngineResult.getStatus() == SSLEngineResult.Status.CLOSED && sslEngine.getHandshakeStatus() == HandshakeStatus.NOT_HANDSHAKING){
try {
close();
} catch (IOException e) {
//Not really interesting
}
}
do {
rem = inData.remaining();
readEngineResult = sslEngine.unwrap( inCrypt, inData );
} while ( readEngineResult.getStatus() == SSLEngineResult.Status.OK && ( rem != inData.remaining() || sslEngine.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP ) );
inData.flip();
return inData;
}
public int write( ByteBuffer src ) throws IOException {
if( !isHandShakeComplete() ) {
processHandshake();
return 0;
}
// assert ( bufferallocations > 1 ); //see #190
//if( bufferallocations <= 1 ) {
// createBuffers( sslEngine.getSession() );
//}
int num = socketChannel.write( wrap( src ) );
if (writeEngineResult.getStatus() == SSLEngineResult.Status.CLOSED) {
throw new EOFException("Connection is closed");
}
return num;
}
/**
* Start SSL shutdown process.
*
* @return <tt>true</tt> if shutdown process is started.
* <tt>false</tt> if shutdown process is already finished.
* @throws SSLException on errors
*/
boolean closeOutbound() throws SSLException {
if (sslEngine == null || sslEngine.isOutboundDone())
return false;
sslEngine.closeOutbound();
createOutNetBuffer(0);
for (;;) {
SSLEngineResult result = sslEngine.wrap(SimpleBufferAllocator.emptyBuffer.buf(), outNetBuffer.buf());
if (result.getStatus() != Status.BUFFER_OVERFLOW) {
if (result.getStatus() != Status.CLOSED)
throw new SSLException("improper close state: " + result);
break;
}
outNetBuffer = IoBuffer.reallocate(outNetBuffer, outNetBuffer.capacity() << 1);
outNetBuffer.limit(outNetBuffer.capacity());
}
outNetBuffer.flip();
return true;
}
/**
* Perform handshake unwrap
* @param doread boolean
* @return the result
* @throws IOException An IO error occurred
*/
protected SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
if (netInBuffer.position() == netInBuffer.limit()) {
//clear the buffer if we have emptied it out on data
netInBuffer.clear();
}
if (doread) {
//if we have data to read, read it
int read = sc.read(netInBuffer);
if (read == -1) {
throw new IOException(sm.getString("channel.nio.ssl.eofDuringHandshake"));
}
}
SSLEngineResult result;
boolean cont = false;
//loop while we can perform pure SSLEngine data
do {
//prepare the buffer with the incoming data
netInBuffer.flip();
//call unwrap
getBufHandler().configureReadBufferForWrite();
result = sslEngine.unwrap(netInBuffer, getBufHandler().getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
handshakeStatus = result.getHandshakeStatus();
if ( result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
//execute tasks if we need to
handshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
}while ( cont );
return result;
}