43 import java.nio.channels.*;
44 import javax.net.ssl.*;
45 import javax.net.ssl.SSLEngineResult.*;
104 class ChannelIOSecure
extends ChannelIO {
106 private SSLEngine sslEngine =
null;
108 private int appBBSize;
109 private int netBBSize;
120 private ByteBuffer inNetBB;
121 private ByteBuffer outNetBB;
128 private static ByteBuffer hsBB = ByteBuffer.allocate(0);
133 private ByteBuffer fileChannelBB =
null;
144 private HandshakeStatus initialHSStatus;
145 private boolean initialHSComplete;
151 private boolean shutdown =
false;
156 protected ChannelIOSecure(SocketChannel sc,
boolean blocking,
157 SSLContext sslc)
throws IOException {
165 sslEngine = sslc.createSSLEngine();
166 sslEngine.setUseClientMode(
false);
167 initialHSStatus = HandshakeStatus.NEED_UNWRAP;
168 initialHSComplete =
false;
173 netBBSize = sslEngine.getSession().getPacketBufferSize();
174 inNetBB = ByteBuffer.allocate(netBBSize);
175 outNetBB = ByteBuffer.allocate(netBBSize);
176 outNetBB.position(0);
187 static ChannelIOSecure getInstance(SocketChannel sc,
boolean blocking,
188 SSLContext sslc)
throws IOException {
190 ChannelIOSecure cio =
new ChannelIOSecure(sc, blocking, sslc);
195 cio.appBBSize = cio.sslEngine.getSession().getApplicationBufferSize();
196 cio.requestBB = ByteBuffer.allocate(cio.appBBSize);
205 protected void resizeRequestBB() {
206 resizeRequestBB(appBBSize);
212 private void resizeResponseBB() {
213 ByteBuffer bb = ByteBuffer.allocate(netBBSize);
224 private boolean tryFlush(ByteBuffer bb)
throws IOException {
226 return !bb.hasRemaining();
235 boolean doHandshake() throws IOException {
236 return doHandshake(
null);
256 boolean doHandshake(SelectionKey sk)
throws IOException {
258 SSLEngineResult result;
260 if (initialHSComplete) {
261 return initialHSComplete;
268 if (outNetBB.hasRemaining()) {
270 if (!tryFlush(outNetBB)) {
276 switch (initialHSStatus) {
282 initialHSComplete =
true;
287 sk.interestOps(SelectionKey.OP_READ);
292 return initialHSComplete;
296 switch (initialHSStatus) {
299 if (sc.read(inNetBB) == -1) {
300 sslEngine.closeInbound();
301 return initialHSComplete;
305 while (initialHSStatus == HandshakeStatus.NEED_UNWRAP) {
308 result = sslEngine.unwrap(inNetBB, requestBB);
311 initialHSStatus = result.getHandshakeStatus();
313 switch (result.getStatus()) {
316 switch (initialHSStatus) {
317 case NOT_HANDSHAKING:
318 throw new IOException(
319 "Not handshaking during initial handshake");
322 initialHSStatus = doTasks();
326 initialHSComplete =
true;
332 case BUFFER_UNDERFLOW:
334 netBBSize = sslEngine.getSession().getPacketBufferSize();
335 if (netBBSize > inNetBB.capacity()) {
343 sk.interestOps(SelectionKey.OP_READ);
347 case BUFFER_OVERFLOW:
350 sslEngine.getSession().getApplicationBufferSize();
354 throw new IOException(
"Received" + result.getStatus() +
355 "during initial handshaking");
362 if (initialHSStatus != HandshakeStatus.NEED_WRAP) {
373 result = sslEngine.wrap(hsBB, outNetBB);
376 initialHSStatus = result.getHandshakeStatus();
378 switch (result.getStatus()) {
381 if (initialHSStatus == HandshakeStatus.NEED_TASK) {
382 initialHSStatus = doTasks();
386 sk.interestOps(SelectionKey.OP_WRITE);
392 throw new IOException(
"Received" + result.getStatus() +
393 "during initial handshaking");
398 throw new RuntimeException(
"Invalid Handshaking State" +
402 return initialHSComplete;
408 private SSLEngineResult.HandshakeStatus doTasks() {
416 while ((runnable = sslEngine.getDelegatedTask()) !=
null) {
419 return sslEngine.getHandshakeStatus();
431 int read() throws IOException {
432 SSLEngineResult result;
434 if (!initialHSComplete) {
435 throw new IllegalStateException();
438 int pos = requestBB.position();
440 if (sc.read(inNetBB) == -1) {
441 sslEngine.closeInbound();
448 result = sslEngine.unwrap(inNetBB, requestBB);
457 switch (result.getStatus()) {
459 case BUFFER_OVERFLOW:
461 appBBSize = sslEngine.getSession().getApplicationBufferSize();
464 case BUFFER_UNDERFLOW:
466 netBBSize = sslEngine.getSession().getPacketBufferSize();
467 if (netBBSize > inNetBB.capacity()) {
473 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
479 throw new IOException(
"sslEngine error during data read: " +
482 }
while ((inNetBB.position() != 0) &&
483 result.getStatus() != Status.BUFFER_UNDERFLOW);
485 return (requestBB.position() - pos);
491 int write(ByteBuffer src)
throws IOException {
493 if (!initialHSComplete) {
494 throw new IllegalStateException();
508 private int doWrite(ByteBuffer src)
throws IOException {
511 if (outNetBB.hasRemaining() && !tryFlush(outNetBB)) {
520 SSLEngineResult result = sslEngine.wrap(src, outNetBB);
521 retValue = result.bytesConsumed();
525 switch (result.getStatus()) {
528 if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK) {
534 throw new IOException(
"sslEngine error during data write: " +
543 if (outNetBB.hasRemaining()) {
562 long transferTo(FileChannel fc,
long pos,
long len)
throws IOException {
564 if (!initialHSComplete) {
565 throw new IllegalStateException();
568 if (fileChannelBB ==
null) {
569 fileChannelBB = ByteBuffer.allocate(appBBSize);
570 fileChannelBB.limit(0);
573 fileChannelBB.compact();
574 int fileRead = fc.read(fileChannelBB);
575 fileChannelBB.flip();
582 doWrite(fileChannelBB);
592 boolean dataFlush() throws IOException {
593 boolean fileFlushed =
true;
595 if ((fileChannelBB !=
null) && fileChannelBB.hasRemaining()) {
596 doWrite(fileChannelBB);
597 fileFlushed = !fileChannelBB.hasRemaining();
598 }
else if (outNetBB.hasRemaining()) {
602 return (fileFlushed && !outNetBB.hasRemaining());
613 boolean shutdown() throws IOException {
616 sslEngine.closeOutbound();
620 if (outNetBB.hasRemaining() && tryFlush(outNetBB)) {
629 SSLEngineResult result = sslEngine.wrap(hsBB, outNetBB);
630 if (result.getStatus() != Status.CLOSED) {
631 throw new SSLException(
"Improper close state");
639 if (outNetBB.hasRemaining()) {
643 return (!outNetBB.hasRemaining() &&
644 (result.getHandshakeStatus() != HandshakeStatus.NEED_WRAP));