Methods Summary |
---|
public void | close()Sends a SSL close message, will not physically close the connection here.
To close the connection, you could do something like
close();
while (isOpen() && !myTimeoutFunction()) Thread.sleep(25);
if ( isOpen() ) close(true); //forces a close if you timed out
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 void | close(boolean force)Force a close, can throw an IOException
try {
close();
}finally {
if ( force || closed ) {
closed = true;
sc.socket().close();
sc.close();
}
}
|
public boolean | flush(boolean block, java.nio.channels.Selector s, long timeout)returns true if the network buffer has
been flushed out and is empty
if (!block) {
flush(netOutBuffer);
} else {
pool.write(netOutBuffer, this, s, timeout);
}
return !netOutBuffer.hasRemaining();
|
protected boolean | flush(java.nio.ByteBuffer buf)Flushes the buffer to the network, non blocking
int remaining = buf.remaining();
if ( remaining > 0 ) {
int written = sc.write(buf);
return written >= remaining;
}else {
return true;
}
|
public org.apache.tomcat.util.net.SecureNioChannel$ApplicationBufferHandler | getBufHandler()
return bufHandler;
|
public int | getBufferSize()
int size = super.getBufferSize();
size += netInBuffer!=null?netInBuffer.capacity():0;
size += netOutBuffer!=null?netOutBuffer.capacity():0;
return size;
|
public java.nio.ByteBuffer | getEmptyBuf()
return emptyBuf;
|
public java.nio.channels.SocketChannel | getIOChannel()
return sc;
|
public javax.net.ssl.SSLEngine | getSslEngine()
return sslEngine;
|
public int | handshake(boolean read, boolean write)Performs SSL handshake, non blocking, but performs NEED_TASK on the same thread.
Hence, you should never call this method using your Acceptor thread, as you would slow down
your system significantly.
The return for this operation is 0 if the handshake is complete and a positive value if it is not complete.
In the event of a positive value coming back, reregister the selection key for the return values interestOps.
if ( initHandshakeComplete ) return 0; //we have done our initial handshake
if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still have data to write
SSLEngineResult handshake = null;
while (!initHandshakeComplete) {
switch ( initHandshakeStatus ) {
case NOT_HANDSHAKING: {
//should never happen
throw new IOException("NOT_HANDSHAKING during handshake");
}
case FINISHED: {
//we are complete if we have delivered the last package
initHandshakeComplete = !netOutBuffer.hasRemaining();
//return 0 if we are complete, otherwise we still have data to write
return initHandshakeComplete?0:SelectionKey.OP_WRITE;
}
case NEED_WRAP: {
//perform the wrap function
handshake = handshakeWrap(write);
if ( handshake.getStatus() == Status.OK ){
if (initHandshakeStatus == HandshakeStatus.NEED_TASK)
initHandshakeStatus = tasks();
} else {
//wrap should always work with our buffers
throw new IOException("Unexpected status:" + handshake.getStatus() + " during handshake WRAP.");
}
if ( initHandshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) {
//should actually return OP_READ if we have NEED_UNWRAP
return SelectionKey.OP_WRITE;
}
//fall down to NEED_UNWRAP on the same call, will result in a
//BUFFER_UNDERFLOW if it needs data
}
case NEED_UNWRAP: {
//perform the unwrap function
handshake = handshakeUnwrap(read);
if ( handshake.getStatus() == Status.OK ) {
if (initHandshakeStatus == HandshakeStatus.NEED_TASK)
initHandshakeStatus = tasks();
} else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){
//read more data, reregister for OP_READ
return SelectionKey.OP_READ;
} else {
throw new IOException("Invalid handshake status:"+initHandshakeStatus+" during handshake UNWRAP.");
}//switch
break;
}
case NEED_TASK: {
initHandshakeStatus = tasks();
break;
}
default: throw new IllegalStateException("Invalid handshake status:"+initHandshakeStatus);
}//switch
}//while
//return 0 if we are complete, otherwise reregister for any activity that
//would cause this method to be called again.
return initHandshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
|
protected javax.net.ssl.SSLEngineResult | handshakeUnwrap(boolean doread)Perform handshake unwrap
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("EOF encountered during handshake.");
}
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
result = sslEngine.unwrap(netInBuffer, bufHandler.getReadBuffer());
//compact the buffer, this is an optional method, wonder what would happen if we didn't
netInBuffer.compact();
//read in the status
initHandshakeStatus = result.getHandshakeStatus();
if ( result.getStatus() == SSLEngineResult.Status.OK &&
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
//execute tasks if we need to
initHandshakeStatus = tasks();
}
//perform another unwrap?
cont = result.getStatus() == SSLEngineResult.Status.OK &&
initHandshakeStatus == HandshakeStatus.NEED_UNWRAP;
}while ( cont );
return result;
|
protected javax.net.ssl.SSLEngineResult | handshakeWrap(boolean doWrite)Performs the WRAP function
//this should never be called with a network buffer that contains data
//so we can clear it here.
netOutBuffer.clear();
//perform the wrap
SSLEngineResult result = sslEngine.wrap(bufHandler.getWriteBuffer(), netOutBuffer);
//prepare the results to be written
netOutBuffer.flip();
//set the status
initHandshakeStatus = result.getHandshakeStatus();
//optimization, if we do have a writable channel, write it now
if ( doWrite ) flush(netOutBuffer);
return result;
|
public boolean | isClosing()
return closing;
|
public boolean | isInitHandshakeComplete()
return initHandshakeComplete;
|
public int | read(java.nio.ByteBuffer dst)Reads a sequence of bytes from this channel into the given buffer.
//if we want to take advantage of the expand function, make sure we only use the ApplicationBufferHandler's buffers
if ( dst != bufHandler.getReadBuffer() ) throw new IllegalArgumentException("You can only read using the application read buffer provided by the handler.");
//are we in the middle of closing or closed?
if ( closing || closed) return -1;
//did we finish our handshake?
if (!initHandshakeComplete) throw new IllegalStateException("Handshake incomplete, you must complete handshake before reading data.");
//read from the network
int netread = sc.read(netInBuffer);
//did we reach EOF? if so send EOF up one layer.
if (netread == -1) return -1;
//the data read
int read = 0;
//the SSL engine result
SSLEngineResult unwrap;
do {
//prepare the buffer
netInBuffer.flip();
//unwrap the data
unwrap = sslEngine.unwrap(netInBuffer, dst);
//compact the buffer
netInBuffer.compact();
if ( unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW ) {
//we did receive some data, add it to our total
read += unwrap.bytesProduced();
//perform any tasks if needed
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
//if we need more network data, then bail out for now.
if ( unwrap.getStatus() == Status.BUFFER_UNDERFLOW ) break;
}else {
//here we should trap BUFFER_OVERFLOW and call expand on the buffer
//for now, throw an exception, as we initialized the buffers
//in the constructor
throw new IOException("Unable to unwrap data, invalid status: " + unwrap.getStatus());
}
} while ( (netInBuffer.position() != 0)); //continue to unwrapping as long as the input buffer has stuff
return (read);
|
public void | reset(javax.net.ssl.SSLEngine engine)
this.sslEngine = engine;
reset();
|
public void | reset()
super.reset();
netOutBuffer.position(0);
netOutBuffer.limit(0);
netInBuffer.position(0);
netInBuffer.limit(0);
initHandshakeComplete = false;
closed = false;
closing = false;
//initiate handshake
sslEngine.beginHandshake();
initHandshakeStatus = sslEngine.getHandshakeStatus();
|
public void | setBufHandler(org.apache.tomcat.util.net.SecureNioChannel$ApplicationBufferHandler bufHandler)
this.bufHandler = bufHandler;
|
protected javax.net.ssl.SSLEngineResult.HandshakeStatus | tasks()Executes all the tasks needed on the same thread.
Runnable r = null;
while ( (r = sslEngine.getDelegatedTask()) != null) {
r.run();
}
return sslEngine.getHandshakeStatus();
|
public int | write(java.nio.ByteBuffer src)Writes a sequence of bytes to this channel from the given buffer.
//make sure we can handle expand, and that we only use on buffer
if ( src != bufHandler.getWriteBuffer() ) throw new IllegalArgumentException("You can only write using the application write buffer provided by the handler.");
//are we closing or closed?
if ( closing || closed) throw new IOException("Channel is in closing state.");
//the number of bytes written
int written = 0;
if (!flush(netOutBuffer)) {
//we haven't emptied out the buffer yet
return written;
}
/*
* The data buffer is empty, we can reuse the entire buffer.
*/
netOutBuffer.clear();
SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
written = result.bytesConsumed();
netOutBuffer.flip();
if (result.getStatus() == Status.OK) {
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
} else {
throw new IOException("Unable to wrap data, invalid engine state: " +result.getStatus());
}
//force a flush
flush(netOutBuffer);
return written;
|