1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.jboss.netty.handler.ssl;
17
18 import static org.jboss.netty.channel.Channels.*;
19
20 import java.io.IOException;
21 import java.nio.ByteBuffer;
22 import java.nio.channels.ClosedChannelException;
23 import java.util.LinkedList;
24 import java.util.Queue;
25 import java.util.concurrent.Executor;
26 import java.util.concurrent.atomic.AtomicBoolean;
27 import java.util.regex.Pattern;
28
29 import javax.net.ssl.SSLEngine;
30 import javax.net.ssl.SSLEngineResult;
31 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
32 import javax.net.ssl.SSLEngineResult.Status;
33 import javax.net.ssl.SSLException;
34
35 import org.jboss.netty.buffer.ChannelBuffer;
36 import org.jboss.netty.buffer.ChannelBuffers;
37 import org.jboss.netty.channel.Channel;
38 import org.jboss.netty.channel.ChannelDownstreamHandler;
39 import org.jboss.netty.channel.ChannelEvent;
40 import org.jboss.netty.channel.ChannelFuture;
41 import org.jboss.netty.channel.ChannelFutureListener;
42 import org.jboss.netty.channel.ChannelHandlerContext;
43 import org.jboss.netty.channel.ChannelPipeline;
44 import org.jboss.netty.channel.ChannelStateEvent;
45 import org.jboss.netty.channel.Channels;
46 import org.jboss.netty.channel.DownstreamMessageEvent;
47 import org.jboss.netty.channel.ExceptionEvent;
48 import org.jboss.netty.channel.LifeCycleAwareChannelHandler;
49 import org.jboss.netty.channel.MessageEvent;
50 import org.jboss.netty.handler.codec.frame.FrameDecoder;
51 import org.jboss.netty.logging.InternalLogger;
52 import org.jboss.netty.logging.InternalLoggerFactory;
53 import org.jboss.netty.util.internal.LinkedTransferQueue;
54 import org.jboss.netty.util.internal.NonReentrantLock;
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144 public class SslHandler extends FrameDecoder
145 implements ChannelDownstreamHandler,
146 LifeCycleAwareChannelHandler {
147
148 private static final InternalLogger logger =
149 InternalLoggerFactory.getInstance(SslHandler.class);
150
151 private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
152
153 private static final Pattern IGNORABLE_ERROR_MESSAGE = Pattern.compile(
154 "^.*(?:connection.*reset|connection.*closed|broken.*pipe).*$",
155 Pattern.CASE_INSENSITIVE);
156
157 private static SslBufferPool defaultBufferPool;
158
159
160
161
162
163 public static synchronized SslBufferPool getDefaultBufferPool() {
164 if (defaultBufferPool == null) {
165 defaultBufferPool = new SslBufferPool();
166 }
167 return defaultBufferPool;
168 }
169
170 private volatile ChannelHandlerContext ctx;
171 private final SSLEngine engine;
172 private final SslBufferPool bufferPool;
173 private final Executor delegatedTaskExecutor;
174 private final boolean startTls;
175
176 private volatile boolean enableRenegotiation;
177
178 final Object handshakeLock = new Object();
179 private boolean handshaking;
180 private volatile boolean handshaken;
181 private volatile ChannelFuture handshakeFuture;
182
183 private final AtomicBoolean sentFirstMessage = new AtomicBoolean();
184 private final AtomicBoolean sentCloseNotify = new AtomicBoolean();
185 int ignoreClosedChannelException;
186 final Object ignoreClosedChannelExceptionLock = new Object();
187 private final Queue<PendingWrite> pendingUnencryptedWrites = new LinkedList<PendingWrite>();
188 private final Queue<MessageEvent> pendingEncryptedWrites = new LinkedTransferQueue<MessageEvent>();
189 private final NonReentrantLock pendingEncryptedWritesLock = new NonReentrantLock();
190
191
192
193
194
195
196 public SslHandler(SSLEngine engine) {
197 this(engine, getDefaultBufferPool(), ImmediateExecutor.INSTANCE);
198 }
199
200
201
202
203
204
205
206
207 public SslHandler(SSLEngine engine, SslBufferPool bufferPool) {
208 this(engine, bufferPool, ImmediateExecutor.INSTANCE);
209 }
210
211
212
213
214
215
216
217
218 public SslHandler(SSLEngine engine, boolean startTls) {
219 this(engine, getDefaultBufferPool(), startTls);
220 }
221
222
223
224
225
226
227
228
229
230
231 public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls) {
232 this(engine, bufferPool, startTls, ImmediateExecutor.INSTANCE);
233 }
234
235
236
237
238
239
240
241
242
243
244 public SslHandler(SSLEngine engine, Executor delegatedTaskExecutor) {
245 this(engine, getDefaultBufferPool(), delegatedTaskExecutor);
246 }
247
248
249
250
251
252
253
254
255
256
257
258
259
260 public SslHandler(SSLEngine engine, SslBufferPool bufferPool, Executor delegatedTaskExecutor) {
261 this(engine, bufferPool, false, delegatedTaskExecutor);
262 }
263
264
265
266
267
268
269
270
271
272
273
274
275
276 public SslHandler(SSLEngine engine, boolean startTls, Executor delegatedTaskExecutor) {
277 this(engine, getDefaultBufferPool(), startTls, delegatedTaskExecutor);
278 }
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295 public SslHandler(SSLEngine engine, SslBufferPool bufferPool, boolean startTls, Executor delegatedTaskExecutor) {
296 if (engine == null) {
297 throw new NullPointerException("engine");
298 }
299 if (bufferPool == null) {
300 throw new NullPointerException("bufferPool");
301 }
302 if (delegatedTaskExecutor == null) {
303 throw new NullPointerException("delegatedTaskExecutor");
304 }
305 this.engine = engine;
306 this.bufferPool = bufferPool;
307 this.delegatedTaskExecutor = delegatedTaskExecutor;
308 this.startTls = startTls;
309 }
310
311
312
313
314 public SSLEngine getEngine() {
315 return engine;
316 }
317
318
319
320
321
322
323
324 public ChannelFuture handshake() {
325 if (handshaken && !isEnableRenegotiation()) {
326 throw new IllegalStateException("renegotiation disabled");
327 }
328
329 ChannelHandlerContext ctx = this.ctx;
330 Channel channel = ctx.getChannel();
331 ChannelFuture handshakeFuture;
332 synchronized (handshakeLock) {
333 if (handshaking) {
334 return this.handshakeFuture;
335 } else {
336 handshaking = true;
337 try {
338 engine.beginHandshake();
339 runDelegatedTasks();
340 handshakeFuture = this.handshakeFuture = future(channel);
341 } catch (SSLException e) {
342 handshakeFuture = this.handshakeFuture = failedFuture(channel, e);
343 }
344 }
345 }
346
347 try {
348 wrapNonAppData(ctx, channel);
349 } catch (SSLException e) {
350 handshakeFuture.setFailure(e);
351 }
352 return handshakeFuture;
353 }
354
355
356
357
358 @Deprecated
359 public ChannelFuture handshake(@SuppressWarnings("unused") Channel channel) {
360 return handshake();
361 }
362
363
364
365
366
367 public ChannelFuture close() {
368 ChannelHandlerContext ctx = this.ctx;
369 Channel channel = ctx.getChannel();
370 try {
371 engine.closeOutbound();
372 return wrapNonAppData(ctx, channel);
373 } catch (SSLException e) {
374 return failedFuture(channel, e);
375 }
376 }
377
378
379
380
381 @Deprecated
382 public ChannelFuture close(@SuppressWarnings("unused") Channel channel) {
383 return close();
384 }
385
386
387
388
389 public boolean isEnableRenegotiation() {
390 return enableRenegotiation;
391 }
392
393
394
395
396 public void setEnableRenegotiation(boolean enableRenegotiation) {
397 this.enableRenegotiation = enableRenegotiation;
398 }
399
400 public void handleDownstream(
401 final ChannelHandlerContext context, final ChannelEvent evt) throws Exception {
402 if (evt instanceof ChannelStateEvent) {
403 ChannelStateEvent e = (ChannelStateEvent) evt;
404 switch (e.getState()) {
405 case OPEN:
406 case CONNECTED:
407 case BOUND:
408 if (Boolean.FALSE.equals(e.getValue()) || e.getValue() == null) {
409 closeOutboundAndChannel(context, e);
410 return;
411 }
412 }
413 }
414 if (!(evt instanceof MessageEvent)) {
415 context.sendDownstream(evt);
416 return;
417 }
418
419 MessageEvent e = (MessageEvent) evt;
420 if (!(e.getMessage() instanceof ChannelBuffer)) {
421 context.sendDownstream(evt);
422 return;
423 }
424
425
426
427 if (startTls && sentFirstMessage.compareAndSet(false, true)) {
428 context.sendDownstream(evt);
429 return;
430 }
431
432
433 ChannelBuffer msg = (ChannelBuffer) e.getMessage();
434 PendingWrite pendingWrite;
435
436 if (msg.readable()) {
437 pendingWrite = new PendingWrite(evt.getFuture(), msg.toByteBuffer(msg.readerIndex(), msg.readableBytes()));
438 } else {
439 pendingWrite = new PendingWrite(evt.getFuture(), null);
440 }
441 synchronized (pendingUnencryptedWrites) {
442 boolean offered = pendingUnencryptedWrites.offer(pendingWrite);
443 assert offered;
444 }
445
446 wrap(context, evt.getChannel());
447 }
448
449 @Override
450 public void channelDisconnected(ChannelHandlerContext ctx,
451 ChannelStateEvent e) throws Exception {
452
453
454
455 synchronized (handshakeLock) {
456 if (handshaking) {
457 handshakeFuture.setFailure(new ClosedChannelException());
458 }
459 }
460
461 try {
462 super.channelDisconnected(ctx, e);
463 } finally {
464 unwrap(ctx, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0);
465 engine.closeOutbound();
466 if (!sentCloseNotify.get() && handshaken) {
467 try {
468 engine.closeInbound();
469 } catch (SSLException ex) {
470 logger.debug("Failed to clean up SSLEngine.", ex);
471 }
472 }
473 }
474 }
475
476 @Override
477 public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e)
478 throws Exception {
479
480 Throwable cause = e.getCause();
481 if (cause instanceof IOException) {
482 if (cause instanceof ClosedChannelException) {
483 synchronized (ignoreClosedChannelExceptionLock) {
484 if (ignoreClosedChannelException > 0) {
485 ignoreClosedChannelException --;
486 logger.debug(
487 "Swallowing an exception raised while " +
488 "writing non-app data", cause);
489 return;
490 }
491 }
492 } else if (engine.isOutboundDone()) {
493 String message = String.valueOf(cause.getMessage()).toLowerCase();
494 if (IGNORABLE_ERROR_MESSAGE.matcher(message).matches()) {
495
496
497 logger.debug(
498 "Swallowing a 'connection reset by peer / " +
499 "broken pipe' error occurred while writing " +
500 "'closure_notify'", cause);
501
502
503
504 Channels.close(ctx, succeededFuture(e.getChannel()));
505 return;
506 }
507 }
508 }
509
510 ctx.sendUpstream(e);
511 }
512
513 @Override
514 protected Object decode(
515 final ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer) throws Exception {
516
517 if (buffer.readableBytes() < 5) {
518 return null;
519 }
520
521 int packetLength = 0;
522
523
524 boolean tls;
525 switch (buffer.getUnsignedByte(buffer.readerIndex())) {
526 case 20:
527 case 21:
528 case 22:
529 case 23:
530 tls = true;
531 break;
532 default:
533
534 tls = false;
535 }
536
537 if (tls) {
538
539 int majorVersion = buffer.getUnsignedByte(buffer.readerIndex() + 1);
540 if (majorVersion >= 3 && majorVersion < 10) {
541
542 packetLength = (buffer.getShort(buffer.readerIndex() + 3) & 0xFFFF) + 5;
543 if (packetLength <= 5) {
544
545 tls = false;
546 }
547 } else {
548
549 tls = false;
550 }
551 }
552
553 if (!tls) {
554
555 boolean sslv2 = true;
556 int headerLength = (buffer.getUnsignedByte(
557 buffer.readerIndex()) & 0x80) != 0 ? 2 : 3;
558 int majorVersion = buffer.getUnsignedByte(
559 buffer.readerIndex() + headerLength + 1);
560 if (majorVersion >= 2 && majorVersion < 10) {
561
562 if (headerLength == 2) {
563 packetLength = (buffer.getShort(buffer.readerIndex()) & 0x7FFF) + 2;
564 } else {
565 packetLength = (buffer.getShort(buffer.readerIndex()) & 0x3FFF) + 3;
566 }
567 if (packetLength <= headerLength) {
568 sslv2 = false;
569 }
570 } else {
571 sslv2 = false;
572 }
573
574 if (!sslv2) {
575
576 SSLException e = new SSLException(
577 "not an SSL/TLS record: " + ChannelBuffers.hexDump(buffer));
578 buffer.skipBytes(buffer.readableBytes());
579 throw e;
580 }
581 }
582
583 assert packetLength > 0;
584
585 if (buffer.readableBytes() < packetLength) {
586 return null;
587 }
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603 final int packetOffset = buffer.readerIndex();
604 buffer.skipBytes(packetLength);
605 return unwrap(ctx, channel, buffer, packetOffset, packetLength);
606 }
607
608 private ChannelFuture wrap(ChannelHandlerContext context, Channel channel)
609 throws SSLException {
610
611 ChannelFuture future = null;
612 ChannelBuffer msg;
613 ByteBuffer outNetBuf = bufferPool.acquire();
614 boolean success = true;
615 boolean offered = false;
616 boolean needsUnwrap = false;
617 try {
618 loop:
619 for (;;) {
620
621
622
623 synchronized (pendingUnencryptedWrites) {
624 PendingWrite pendingWrite = pendingUnencryptedWrites.peek();
625 if (pendingWrite == null) {
626 break;
627 }
628
629 ByteBuffer outAppBuf = pendingWrite.outAppBuf;
630 if (outAppBuf == null) {
631
632 pendingUnencryptedWrites.remove();
633 offerEncryptedWriteRequest(
634 new DownstreamMessageEvent(
635 channel, pendingWrite.future,
636 ChannelBuffers.EMPTY_BUFFER,
637 channel.getRemoteAddress()));
638 offered = true;
639 } else {
640 SSLEngineResult result = null;
641 try {
642 synchronized (handshakeLock) {
643 result = engine.wrap(outAppBuf, outNetBuf);
644 }
645 } finally {
646 if (!outAppBuf.hasRemaining()) {
647 pendingUnencryptedWrites.remove();
648 }
649 }
650
651 if (result.bytesProduced() > 0) {
652 outNetBuf.flip();
653 msg = ChannelBuffers.buffer(outNetBuf.remaining());
654 msg.writeBytes(outNetBuf.array(), 0, msg.capacity());
655 outNetBuf.clear();
656
657 if (pendingWrite.outAppBuf.hasRemaining()) {
658
659
660 future = succeededFuture(channel);
661 } else {
662 future = pendingWrite.future;
663 }
664
665 MessageEvent encryptedWrite = new DownstreamMessageEvent(
666 channel, future, msg, channel.getRemoteAddress());
667 offerEncryptedWriteRequest(encryptedWrite);
668 offered = true;
669 } else {
670 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
671 handleRenegotiation(handshakeStatus);
672 switch (handshakeStatus) {
673 case NEED_WRAP:
674 if (outAppBuf.hasRemaining()) {
675 break;
676 } else {
677 break loop;
678 }
679 case NEED_UNWRAP:
680 needsUnwrap = true;
681 break loop;
682 case NEED_TASK:
683 runDelegatedTasks();
684 break;
685 case FINISHED:
686 case NOT_HANDSHAKING:
687 if (handshakeStatus == HandshakeStatus.FINISHED) {
688 setHandshakeSuccess(channel);
689 }
690 if (result.getStatus() == Status.CLOSED) {
691 success = false;
692 }
693 break loop;
694 default:
695 throw new IllegalStateException(
696 "Unknown handshake status: " +
697 handshakeStatus);
698 }
699 }
700 }
701 }
702 }
703 } catch (SSLException e) {
704 success = false;
705 setHandshakeFailure(channel, e);
706 throw e;
707 } finally {
708 bufferPool.release(outNetBuf);
709
710 if (offered) {
711 flushPendingEncryptedWrites(context);
712 }
713
714 if (!success) {
715 IllegalStateException cause =
716 new IllegalStateException("SSLEngine already closed");
717
718
719
720
721 for (;;) {
722 PendingWrite pendingWrite;
723 synchronized (pendingUnencryptedWrites) {
724 pendingWrite = pendingUnencryptedWrites.poll();
725 if (pendingWrite == null) {
726 break;
727 }
728 }
729
730 pendingWrite.future.setFailure(cause);
731 }
732 }
733 }
734
735 if (needsUnwrap) {
736 unwrap(context, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0);
737 }
738
739 if (future == null) {
740 future = succeededFuture(channel);
741 }
742 return future;
743 }
744
745 private void offerEncryptedWriteRequest(MessageEvent encryptedWrite) {
746 final boolean locked = pendingEncryptedWritesLock.tryLock();
747 try {
748 pendingEncryptedWrites.offer(encryptedWrite);
749 } finally {
750 if (locked) {
751 pendingEncryptedWritesLock.unlock();
752 }
753 }
754 }
755
756 private void flushPendingEncryptedWrites(ChannelHandlerContext ctx) {
757
758
759
760 if (!pendingEncryptedWritesLock.tryLock()) {
761 return;
762 }
763
764 try {
765 MessageEvent e;
766 while ((e = pendingEncryptedWrites.poll()) != null) {
767 ctx.sendDownstream(e);
768 }
769 } finally {
770 pendingEncryptedWritesLock.unlock();
771 }
772 }
773
774 private ChannelFuture wrapNonAppData(ChannelHandlerContext ctx, Channel channel) throws SSLException {
775 ChannelFuture future = null;
776 ByteBuffer outNetBuf = bufferPool.acquire();
777
778 SSLEngineResult result;
779 try {
780 for (;;) {
781 synchronized (handshakeLock) {
782 result = engine.wrap(EMPTY_BUFFER, outNetBuf);
783 }
784
785 if (result.bytesProduced() > 0) {
786 outNetBuf.flip();
787 ChannelBuffer msg = ChannelBuffers.buffer(outNetBuf.remaining());
788 msg.writeBytes(outNetBuf.array(), 0, msg.capacity());
789 outNetBuf.clear();
790
791 future = future(channel);
792 future.addListener(new ChannelFutureListener() {
793 public void operationComplete(ChannelFuture future)
794 throws Exception {
795 if (future.getCause() instanceof ClosedChannelException) {
796 synchronized (ignoreClosedChannelExceptionLock) {
797 ignoreClosedChannelException ++;
798 }
799 }
800 }
801 });
802
803 write(ctx, future, msg);
804 }
805
806 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
807 handleRenegotiation(handshakeStatus);
808 switch (handshakeStatus) {
809 case FINISHED:
810 setHandshakeSuccess(channel);
811 runDelegatedTasks();
812 break;
813 case NEED_TASK:
814 runDelegatedTasks();
815 break;
816 case NEED_UNWRAP:
817 if (!Thread.holdsLock(handshakeLock)) {
818
819
820
821 unwrap(ctx, channel, ChannelBuffers.EMPTY_BUFFER, 0, 0);
822 }
823 break;
824 case NOT_HANDSHAKING:
825 case NEED_WRAP:
826 break;
827 default:
828 throw new IllegalStateException(
829 "Unexpected handshake status: " + handshakeStatus);
830 }
831
832 if (result.bytesProduced() == 0) {
833 break;
834 }
835 }
836 } catch (SSLException e) {
837 setHandshakeFailure(channel, e);
838 throw e;
839 } finally {
840 bufferPool.release(outNetBuf);
841 }
842
843 if (future == null) {
844 future = succeededFuture(channel);
845 }
846
847 return future;
848 }
849
850 private ChannelBuffer unwrap(
851 ChannelHandlerContext ctx, Channel channel, ChannelBuffer buffer, int offset, int length) throws SSLException {
852 ByteBuffer inNetBuf = buffer.toByteBuffer(offset, length);
853 ByteBuffer outAppBuf = bufferPool.acquire();
854
855 try {
856 boolean needsWrap = false;
857 loop:
858 for (;;) {
859 SSLEngineResult result;
860 synchronized (handshakeLock) {
861 if (!handshaken && !handshaking &&
862 !engine.getUseClientMode() &&
863 !engine.isInboundDone() && !engine.isOutboundDone()) {
864 handshake();
865 }
866
867 try {
868 result = engine.unwrap(inNetBuf, outAppBuf);
869 } catch (SSLException e) {
870 throw e;
871 }
872
873 final HandshakeStatus handshakeStatus = result.getHandshakeStatus();
874 handleRenegotiation(handshakeStatus);
875 switch (handshakeStatus) {
876 case NEED_UNWRAP:
877 if (inNetBuf.hasRemaining() && !engine.isInboundDone()) {
878 break;
879 } else {
880 break loop;
881 }
882 case NEED_WRAP:
883 wrapNonAppData(ctx, channel);
884 break;
885 case NEED_TASK:
886 runDelegatedTasks();
887 break;
888 case FINISHED:
889 setHandshakeSuccess(channel);
890 needsWrap = true;
891 break loop;
892 case NOT_HANDSHAKING:
893 needsWrap = true;
894 break loop;
895 default:
896 throw new IllegalStateException(
897 "Unknown handshake status: " + handshakeStatus);
898 }
899 }
900 }
901
902 if (needsWrap) {
903
904
905
906
907
908
909
910
911 if (!Thread.holdsLock(handshakeLock) &&
912 !pendingEncryptedWritesLock.isHeldByCurrentThread()) {
913 wrap(ctx, channel);
914 }
915 }
916
917 outAppBuf.flip();
918
919 if (outAppBuf.hasRemaining()) {
920 ChannelBuffer frame = ChannelBuffers.buffer(outAppBuf.remaining());
921 frame.writeBytes(outAppBuf.array(), 0, frame.capacity());
922 return frame;
923 } else {
924 return null;
925 }
926 } catch (SSLException e) {
927 setHandshakeFailure(channel, e);
928 throw e;
929 } finally {
930 bufferPool.release(outAppBuf);
931 }
932 }
933
934 private void handleRenegotiation(HandshakeStatus handshakeStatus) {
935 if (handshakeStatus == HandshakeStatus.NOT_HANDSHAKING ||
936 handshakeStatus == HandshakeStatus.FINISHED) {
937
938 return;
939 }
940
941 if (!handshaken) {
942
943 return;
944 }
945
946 final boolean renegotiate;
947 synchronized (handshakeLock) {
948 if (handshaking) {
949
950
951 return;
952 }
953
954 if (engine.isInboundDone() || engine.isOutboundDone()) {
955
956 return;
957 }
958
959 if (isEnableRenegotiation()) {
960
961 renegotiate = true;
962 } else {
963
964 renegotiate = false;
965
966 handshaking = true;
967 }
968 }
969
970 if (renegotiate) {
971
972 handshake();
973 } else {
974
975 fireExceptionCaught(
976 ctx, new SSLException(
977 "renegotiation attempted by peer; " +
978 "closing the connection"));
979
980
981 Channels.close(ctx, succeededFuture(ctx.getChannel()));
982 }
983 }
984
985 private void runDelegatedTasks() {
986 for (;;) {
987 final Runnable task;
988 synchronized (handshakeLock) {
989 task = engine.getDelegatedTask();
990 }
991
992 if (task == null) {
993 break;
994 }
995
996 delegatedTaskExecutor.execute(new Runnable() {
997 public void run() {
998 synchronized (handshakeLock) {
999 task.run();
1000 }
1001 }
1002 });
1003 }
1004 }
1005
1006 private void setHandshakeSuccess(Channel channel) {
1007 synchronized (handshakeLock) {
1008 handshaking = false;
1009 handshaken = true;
1010
1011 if (handshakeFuture == null) {
1012 handshakeFuture = future(channel);
1013 }
1014 }
1015
1016 handshakeFuture.setSuccess();
1017 }
1018
1019 private void setHandshakeFailure(Channel channel, SSLException cause) {
1020 synchronized (handshakeLock) {
1021 if (!handshaking) {
1022 return;
1023 }
1024 handshaking = false;
1025 handshaken = false;
1026
1027 if (handshakeFuture == null) {
1028 handshakeFuture = future(channel);
1029 }
1030 }
1031 handshakeFuture.setFailure(cause);
1032 }
1033
1034 private void closeOutboundAndChannel(
1035 final ChannelHandlerContext context, final ChannelStateEvent e) throws SSLException {
1036 if (!e.getChannel().isConnected()) {
1037 context.sendDownstream(e);
1038 return;
1039 }
1040
1041 unwrap(context, e.getChannel(), ChannelBuffers.EMPTY_BUFFER, 0, 0);
1042 if (!engine.isInboundDone()) {
1043 if (sentCloseNotify.compareAndSet(false, true)) {
1044 engine.closeOutbound();
1045 ChannelFuture closeNotifyFuture = wrapNonAppData(context, e.getChannel());
1046 closeNotifyFuture.addListener(
1047 new ClosingChannelFutureListener(context, e));
1048 return;
1049 }
1050 }
1051
1052 context.sendDownstream(e);
1053 }
1054
1055 private static final class PendingWrite {
1056 final ChannelFuture future;
1057 final ByteBuffer outAppBuf;
1058
1059 PendingWrite(ChannelFuture future, ByteBuffer outAppBuf) {
1060 this.future = future;
1061 this.outAppBuf = outAppBuf;
1062 }
1063 }
1064
1065 private static final class ClosingChannelFutureListener implements ChannelFutureListener {
1066
1067 private final ChannelHandlerContext context;
1068 private final ChannelStateEvent e;
1069
1070 ClosingChannelFutureListener(
1071 ChannelHandlerContext context, ChannelStateEvent e) {
1072 this.context = context;
1073 this.e = e;
1074 }
1075
1076 public void operationComplete(ChannelFuture closeNotifyFuture) throws Exception {
1077 if (!(closeNotifyFuture.getCause() instanceof ClosedChannelException)) {
1078 Channels.close(context, e.getFuture());
1079 }
1080 }
1081 }
1082
1083 public void beforeAdd(ChannelHandlerContext ctx) throws Exception {
1084 this.ctx = ctx;
1085 }
1086
1087 public void afterAdd(ChannelHandlerContext ctx) throws Exception {
1088
1089 }
1090
1091 public void beforeRemove(ChannelHandlerContext ctx) throws Exception {
1092
1093 }
1094
1095 public void afterRemove(ChannelHandlerContext ctx) throws Exception {
1096
1097 }
1098 }