1
2
3
4
5
6
7
8
9
10
11
12
13
14 package org.eclipse.jetty.io.nio;
15
16 import java.io.IOException;
17 import java.nio.ByteBuffer;
18 import java.nio.channels.SelectionKey;
19 import java.nio.channels.SocketChannel;
20 import javax.net.ssl.SSLEngine;
21 import javax.net.ssl.SSLEngineResult;
22 import javax.net.ssl.SSLEngineResult.HandshakeStatus;
23 import javax.net.ssl.SSLException;
24 import javax.net.ssl.SSLSession;
25
26 import org.eclipse.jetty.io.Buffer;
27 import org.eclipse.jetty.io.Buffers;
28 import org.eclipse.jetty.io.EofException;
29 import org.eclipse.jetty.util.log.Log;
30 import org.eclipse.jetty.util.log.Logger;
31 import org.eclipse.jetty.util.log.Logger;
32
33
34
35
36
37
38
39
40
41
42
43 public class SslSelectChannelEndPoint extends SelectChannelEndPoint
44 {
45 private static final Logger LOG = Log.getLogger(SslSelectChannelEndPoint.class);
46
47 public static final Logger __log=Log.getLogger("org.eclipse.jetty.io.nio").getLogger("ssl");
48
49 private static final ByteBuffer[] __NO_BUFFERS={};
50
51 private final Buffers _buffers;
52
53 private final SSLEngine _engine;
54 private final SSLSession _session;
55 private volatile NIOBuffer _inNIOBuffer;
56 private volatile NIOBuffer _outNIOBuffer;
57
58 private final ByteBuffer[] _gather=new ByteBuffer[2];
59
60 private boolean _closing=false;
61 private SSLEngineResult _result;
62
63 private boolean _handshook=false;
64 private boolean _allowRenegotiate=false;
65
66 private final boolean _debug = __log.isDebugEnabled();
67
68
69 public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine, int maxIdleTime)
70 throws IOException
71 {
72 super(channel,selectSet,key, maxIdleTime);
73 _buffers=buffers;
74
75
76 _engine=engine;
77 _session=engine.getSession();
78
79 if (_debug) __log.debug(_session+" channel="+channel);
80 }
81
82
83 public SslSelectChannelEndPoint(Buffers buffers,SocketChannel channel, SelectorManager.SelectSet selectSet, SelectionKey key, SSLEngine engine)
84 throws IOException
85 {
86 super(channel,selectSet,key);
87 _buffers=buffers;
88
89
90 _engine=engine;
91 _session=engine.getSession();
92
93 if (_debug) __log.debug(_session+" channel="+channel);
94 }
95
96 int _outCount;
97
98
99 private void needOutBuffer()
100 {
101 synchronized (this)
102 {
103 _outCount++;
104 if (_outNIOBuffer==null)
105 _outNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize());
106 }
107 }
108
109
110 private void freeOutBuffer()
111 {
112 synchronized (this)
113 {
114 if (--_outCount<=0 && _outNIOBuffer!=null && _outNIOBuffer.length()==0)
115 {
116 _buffers.returnBuffer(_outNIOBuffer);
117 _outNIOBuffer=null;
118 _outCount=0;
119 }
120 }
121 }
122
123 int _inCount;
124
125 private void needInBuffer()
126 {
127 synchronized (this)
128 {
129 _inCount++;
130 if(_inNIOBuffer==null)
131 _inNIOBuffer=(NIOBuffer)_buffers.getBuffer(_session.getPacketBufferSize());
132 }
133 }
134
135
136 private void freeInBuffer()
137 {
138 synchronized (this)
139 {
140 if (--_inCount<=0 &&_inNIOBuffer!=null && _inNIOBuffer.length()==0)
141 {
142 _buffers.returnBuffer(_inNIOBuffer);
143 _inNIOBuffer=null;
144 _inCount=0;
145 }
146 }
147 }
148
149
150
151
152
153 public boolean isAllowRenegotiate()
154 {
155 return _allowRenegotiate;
156 }
157
158
159
160
161
162
163
164
165
166 public void setAllowRenegotiate(boolean allowRenegotiate)
167 {
168 _allowRenegotiate = allowRenegotiate;
169 }
170
171
172
173 @Override
174 public boolean isOutputShutdown()
175 {
176 return _engine!=null && _engine.isOutboundDone();
177 }
178
179
180 @Override
181 public boolean isInputShutdown()
182 {
183 return _engine!=null && _engine.isInboundDone();
184 }
185
186
187 @Override
188 public void shutdownOutput() throws IOException
189 {
190 try
191 {
192 sslClose();
193 }
194 finally
195 {
196 super.shutdownOutput();
197 }
198 }
199
200
201 protected void sslClose() throws IOException
202 {
203 if (_closing)
204 return;
205 _closing=true;
206
207
208 long end=System.currentTimeMillis()+getMaxIdleTime();
209 try
210 {
211 while (isOpen() && isBufferingOutput()&& System.currentTimeMillis()<end)
212 {
213 flush();
214 if (isBufferingOutput())
215 {
216 Thread.sleep(50);
217 flush();
218 }
219 }
220
221 _engine.closeOutbound();
222
223 loop: while (isOpen() && !(_engine.isInboundDone() && _engine.isOutboundDone()) && System.currentTimeMillis()<end)
224 {
225 while (isOpen() && isBufferingOutput() && System.currentTimeMillis()<end)
226 {
227 flush();
228 if (isBufferingOutput())
229 Thread.sleep(50);
230 }
231
232 if (_debug) __log.debug(_session+" closing "+_engine.getHandshakeStatus());
233 switch(_engine.getHandshakeStatus())
234 {
235 case FINISHED:
236 case NOT_HANDSHAKING:
237 _handshook=true;
238 break loop;
239
240 case NEED_UNWRAP:
241 Buffer buffer =_buffers.getBuffer(_engine.getSession().getApplicationBufferSize());
242 try
243 {
244 ByteBuffer bbuffer = ((NIOBuffer)buffer).getByteBuffer();
245 if (!unwrap(bbuffer) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP)
246 {
247 break loop;
248 }
249 }
250 catch(SSLException e)
251 {
252 super.close();
253 LOG.ignore(e);
254 }
255 finally
256 {
257 _buffers.returnBuffer(buffer);
258 }
259 break;
260
261 case NEED_TASK:
262 {
263 Runnable task;
264 while ((task=_engine.getDelegatedTask())!=null)
265 {
266 task.run();
267 }
268 break;
269 }
270
271 case NEED_WRAP:
272 {
273 needOutBuffer();
274 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
275 try
276 {
277 if (_outNIOBuffer.length()>0)
278 flush();
279 _outNIOBuffer.compact();
280 int put=_outNIOBuffer.putIndex();
281 out_buffer.position(put);
282 _result=null;
283 _result=_engine.wrap(__NO_BUFFERS,out_buffer);
284 if (_debug) __log.debug(_session+" close wrap "+_result);
285 _outNIOBuffer.setPutIndex(put+_result.bytesProduced());
286 }
287 catch(SSLException e)
288 {
289 super.close();
290 throw e;
291 }
292 finally
293 {
294 out_buffer.position(0);
295 freeOutBuffer();
296 }
297
298 break;
299 }
300 }
301 }
302 }
303 catch (Exception x)
304 {
305 LOG.debug(x);
306 super.close();
307 }
308 }
309
310
311 @Override
312 public void close() throws IOException
313 {
314 try
315 {
316 sslClose();
317 }
318 finally
319 {
320 super.close();
321 }
322 }
323
324
325
326
327
328
329 @Override
330 public int fill(Buffer buffer) throws IOException
331 {
332
333
334
335 final ByteBuffer bbuf=extractInputBuffer(buffer);
336
337
338 int size=buffer.length();
339
340 HandshakeStatus initialStatus = _engine.getHandshakeStatus();
341
342 synchronized (bbuf)
343 {
344 try
345 {
346
347
348
349 unwrap(bbuf);
350
351
352
353 int wraps=0;
354 loop: while (true)
355 {
356
357 if (isBufferingOutput())
358 {
359
360
361
362 flush();
363
364
365
366
367
368 if (isBufferingOutput())
369 break loop;
370 }
371
372
373 switch(_engine.getHandshakeStatus())
374 {
375 case FINISHED:
376 case NOT_HANDSHAKING:
377
378
379 if (_closing)
380 return -1;
381
382
383 break loop;
384
385 case NEED_UNWRAP:
386 checkRenegotiate();
387
388 if (!unwrap(bbuf) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP)
389 {
390
391
392
393 break loop;
394 }
395
396 break;
397
398 case NEED_TASK:
399 {
400
401
402 Runnable task;
403 while ((task=_engine.getDelegatedTask())!=null)
404 {
405 task.run();
406 }
407
408
409 if(initialStatus==HandshakeStatus.NOT_HANDSHAKING &&
410 _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP && wraps==0)
411 {
412
413
414
415
416 if (_debug) __log.warn(_session+" JETTY-567");
417 return -1;
418 }
419 break;
420 }
421
422 case NEED_WRAP:
423 {
424 checkRenegotiate();
425
426
427 wraps++;
428 needOutBuffer();
429 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
430 synchronized(out_buffer)
431 {
432 try
433 {
434
435
436 _outNIOBuffer.compact();
437 int put=_outNIOBuffer.putIndex();
438 out_buffer.position();
439 _result=null;
440 _result=_engine.wrap(__NO_BUFFERS,out_buffer);
441 if (_debug) __log.debug(_session+" fill wrap "+_result);
442 switch(_result.getStatus())
443 {
444 case BUFFER_OVERFLOW:
445 case BUFFER_UNDERFLOW:
446 LOG.warn("wrap {}",_result);
447 case CLOSED:
448 _closing=true;
449 }
450
451 _outNIOBuffer.setPutIndex(put+_result.bytesProduced());
452 }
453 catch(SSLException e)
454 {
455 super.close();
456 throw e;
457 }
458 finally
459 {
460 out_buffer.position(0);
461 }
462 }
463
464
465 flush();
466 freeOutBuffer();
467
468 break;
469 }
470 }
471 }
472 }
473 finally
474 {
475
476 buffer.setPutIndex(bbuf.position());
477 bbuf.position(0);
478 }
479
480
481 int filled=buffer.length()-size;
482 if (filled>0)
483 _handshook=true;
484 return filled;
485 }
486 }
487
488
489 @Override
490 public int flush(Buffer buffer) throws IOException
491 {
492 return flush(buffer,null,null);
493 }
494
495
496
497
498
499 @Override
500 public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException
501 {
502 int consumed=0;
503 int available=header.length();
504 if (buffer!=null)
505 available+=buffer.length();
506
507 needOutBuffer();
508 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
509 loop: while (true)
510 {
511 if (_outNIOBuffer.length()>0)
512 {
513 flush();
514 if (isBufferingOutput())
515 break loop;
516 }
517
518 switch(_engine.getHandshakeStatus())
519 {
520 case FINISHED:
521 case NOT_HANDSHAKING:
522 if (_closing || available==0)
523 {
524 if (consumed==0)
525 consumed= -1;
526 break loop;
527 }
528
529 int c;
530 if (header!=null && header.length()>0)
531 {
532 if (buffer!=null && buffer.length()>0)
533 c=wrap(header,buffer);
534 else
535 c=wrap(header);
536 }
537 else
538 c=wrap(buffer);
539
540
541 if (c>0)
542 {
543 _handshook=true;
544 consumed+=c;
545 available-=c;
546 }
547 else if (c<0)
548 {
549 if (consumed==0)
550 consumed=-1;
551 break loop;
552 }
553
554 break;
555
556 case NEED_UNWRAP:
557 checkRenegotiate();
558 Buffer buf =_buffers.getBuffer(_engine.getSession().getApplicationBufferSize());
559 try
560 {
561 ByteBuffer bbuf = ((NIOBuffer)buf).getByteBuffer();
562 if (!unwrap(bbuf) && _engine.getHandshakeStatus()==HandshakeStatus.NEED_UNWRAP)
563 {
564 break loop;
565 }
566 }
567 finally
568 {
569 _buffers.returnBuffer(buf);
570 }
571
572 break;
573
574 case NEED_TASK:
575 {
576 Runnable task;
577 while ((task=_engine.getDelegatedTask())!=null)
578 {
579 task.run();
580 }
581 break;
582 }
583
584 case NEED_WRAP:
585 {
586 checkRenegotiate();
587 synchronized(out_buffer)
588 {
589 try
590 {
591 _outNIOBuffer.compact();
592 int put=_outNIOBuffer.putIndex();
593 out_buffer.position();
594 _result=null;
595 _result=_engine.wrap(__NO_BUFFERS,out_buffer);
596 if (_debug) __log.debug(_session+" flush wrap "+_result);
597 switch(_result.getStatus())
598 {
599 case BUFFER_OVERFLOW:
600 case BUFFER_UNDERFLOW:
601 LOG.warn("unwrap {}",_result);
602 case CLOSED:
603 _closing=true;
604 }
605 _outNIOBuffer.setPutIndex(put+_result.bytesProduced());
606 }
607 catch(SSLException e)
608 {
609 super.close();
610 throw e;
611 }
612 finally
613 {
614 out_buffer.position(0);
615 }
616 }
617
618 flush();
619 if (isBufferingOutput())
620 break loop;
621
622 break;
623 }
624 }
625 }
626
627 freeOutBuffer();
628 return consumed;
629 }
630
631
632 @Override
633 public void flush() throws IOException
634 {
635 if (_outNIOBuffer==null)
636 return;
637
638 int len=_outNIOBuffer.length();
639 if (isBufferingOutput())
640 {
641 int flushed=super.flush(_outNIOBuffer);
642 if (_debug) __log.debug(_session+" Flushed "+flushed+"/"+len);
643 if (isBufferingOutput())
644 {
645
646 Thread.yield();
647 flushed=super.flush(_outNIOBuffer);
648 if (_debug) __log.debug(_session+" flushed "+flushed+"/"+len);
649 }
650 else if (_closing && !_engine.isOutboundDone())
651 {
652 _engine.closeOutbound();
653 }
654 }
655 }
656
657
658 private void checkRenegotiate() throws IOException
659 {
660 if (_handshook && !_allowRenegotiate && _channel!=null && _channel.isOpen())
661 {
662 LOG.warn("SSL renegotiate denied: "+_channel);
663 super.close();
664 }
665 }
666
667
668 private ByteBuffer extractInputBuffer(Buffer buffer)
669 {
670 assert buffer instanceof NIOBuffer;
671 NIOBuffer nbuf=(NIOBuffer)buffer;
672 ByteBuffer bbuf=nbuf.getByteBuffer();
673 bbuf.position(buffer.putIndex());
674 return bbuf;
675 }
676
677
678
679
680
681 private boolean unwrap(ByteBuffer buffer) throws IOException
682 {
683 needInBuffer();
684 ByteBuffer in_buffer=_inNIOBuffer.getByteBuffer();
685
686 if (_inNIOBuffer.hasContent())
687 _inNIOBuffer.compact();
688 else
689 _inNIOBuffer.clear();
690
691 int total_filled=0;
692 boolean remoteClosed = false;
693
694 while (_inNIOBuffer.space()>0 && super.isOpen())
695 {
696 try
697 {
698 int filled=super.fill(_inNIOBuffer);
699 if (_debug) __log.debug(_session+" unwrap filled "+filled);
700 if (filled < 0)
701 remoteClosed = true;
702
703 if (filled<=0)
704 break;
705 total_filled+=filled;
706 }
707 catch(IOException e)
708 {
709 if (_inNIOBuffer.length()==0)
710 {
711 freeInBuffer();
712 if (_outNIOBuffer!=null)
713 {
714 _outNIOBuffer.clear();
715 freeOutBuffer();
716 }
717 throw e;
718 }
719 break;
720 }
721 }
722
723
724 if (total_filled==0 && _inNIOBuffer.length()==0)
725 {
726 if (isOpen() && remoteClosed)
727 {
728 try
729 {
730 _engine.closeInbound();
731 }
732 catch (SSLException x)
733 {
734
735
736 super.close();
737 }
738 }
739
740 freeInBuffer();
741 freeOutBuffer();
742
743 if (!isOpen())
744 throw new EofException();
745
746 return false;
747 }
748
749
750 try
751 {
752
753
754 in_buffer.position(_inNIOBuffer.getIndex());
755 in_buffer.limit(_inNIOBuffer.putIndex());
756
757
758 _result=_engine.unwrap(in_buffer,buffer);
759 if (_debug) __log.debug(_session+" unwrap unwrap "+_result);
760
761
762 _inNIOBuffer.skip(_result.bytesConsumed());
763 }
764 catch(SSLException e)
765 {
766 LOG.warn(getRemoteAddr() + ":" + getRemotePort() + " " + e);
767 freeOutBuffer();
768 super.close();
769 throw e;
770 }
771 finally
772 {
773
774 in_buffer.position(0);
775 in_buffer.limit(in_buffer.capacity());
776 freeInBuffer();
777 }
778
779
780 switch(_result.getStatus())
781 {
782 case BUFFER_OVERFLOW:
783 throw new IllegalStateException(_result.toString()+" "+buffer.position()+" "+buffer.limit());
784
785 case BUFFER_UNDERFLOW:
786
787
788
789
790 if (LOG.isDebugEnabled()) LOG.debug("unwrap {}",_result);
791 if(!isOpen())
792 {
793 _inNIOBuffer.clear();
794 if (_outNIOBuffer!=null)
795 _outNIOBuffer.clear();
796 throw new EofException();
797 }
798 return (total_filled > 0);
799
800 case CLOSED:
801 _closing=true;
802
803 return total_filled>0 ||_result.bytesConsumed()>0 || _result.bytesProduced()>0;
804 case OK:
805
806 return total_filled>0 ||_result.bytesConsumed()>0 || _result.bytesProduced()>0;
807 default:
808 LOG.warn("unwrap "+_result);
809 throw new IOException(_result.toString());
810 }
811 }
812
813
814
815 private ByteBuffer extractOutputBuffer(Buffer buffer)
816 {
817 if (buffer.buffer() instanceof NIOBuffer)
818 return ((NIOBuffer)buffer.buffer()).getByteBuffer();
819
820 return ByteBuffer.wrap(buffer.array());
821 }
822
823
824 private int wrap(final Buffer header, final Buffer buffer) throws IOException
825 {
826 _gather[0]=extractOutputBuffer(header);
827
828 synchronized(_gather[0])
829 {
830 _gather[0].position(header.getIndex());
831 _gather[0].limit(header.putIndex());
832
833 _gather[1]=extractOutputBuffer(buffer);
834
835 synchronized(_gather[1])
836 {
837 _gather[1].position(buffer.getIndex());
838 _gather[1].limit(buffer.putIndex());
839
840 needOutBuffer();
841 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
842 synchronized(out_buffer)
843 {
844 int consumed=0;
845 try
846 {
847 _outNIOBuffer.clear();
848 out_buffer.position(0);
849 out_buffer.limit(out_buffer.capacity());
850
851 _result=null;
852 _result=_engine.wrap(_gather,out_buffer);
853 if (_debug) __log.debug(_session+" wrap wrap "+_result);
854 _outNIOBuffer.setGetIndex(0);
855 _outNIOBuffer.setPutIndex(_result.bytesProduced());
856 consumed=_result.bytesConsumed();
857 }
858 catch(SSLException e)
859 {
860 LOG.warn(getRemoteAddr()+":"+getRemotePort()+" "+e);
861 super.close();
862 throw e;
863 }
864 finally
865 {
866 out_buffer.position(0);
867
868 if (consumed>0)
869 {
870 int len=consumed<header.length()?consumed:header.length();
871 header.skip(len);
872 consumed-=len;
873 _gather[0].position(0);
874 _gather[0].limit(_gather[0].capacity());
875 }
876 if (consumed>0)
877 {
878 int len=consumed<buffer.length()?consumed:buffer.length();
879 buffer.skip(len);
880 consumed-=len;
881 _gather[1].position(0);
882 _gather[1].limit(_gather[1].capacity());
883 }
884 assert consumed==0;
885
886 freeOutBuffer();
887 }
888 }
889 }
890 }
891
892
893 switch(_result.getStatus())
894 {
895 case BUFFER_OVERFLOW:
896 case BUFFER_UNDERFLOW:
897 LOG.warn("unwrap {}",_result);
898
899 case OK:
900 return _result.bytesConsumed();
901 case CLOSED:
902 _closing=true;
903 return _result.bytesConsumed()>0?_result.bytesConsumed():-1;
904
905 default:
906 LOG.warn("wrap "+_result);
907 throw new IOException(_result.toString());
908 }
909 }
910
911
912 private int wrap(final Buffer buffer) throws IOException
913 {
914 _gather[0]=extractOutputBuffer(buffer);
915 synchronized(_gather[0])
916 {
917 ByteBuffer bb;
918
919 _gather[0].position(buffer.getIndex());
920 _gather[0].limit(buffer.putIndex());
921
922 int consumed=0;
923 needOutBuffer();
924 ByteBuffer out_buffer=_outNIOBuffer.getByteBuffer();
925 synchronized(out_buffer)
926 {
927 try
928 {
929 _outNIOBuffer.clear();
930 out_buffer.position(0);
931 out_buffer.limit(out_buffer.capacity());
932 _result=null;
933 _result=_engine.wrap(_gather[0],out_buffer);
934 if (_debug) __log.debug(_session+" wrap wrap "+_result);
935 _outNIOBuffer.setGetIndex(0);
936 _outNIOBuffer.setPutIndex(_result.bytesProduced());
937 consumed=_result.bytesConsumed();
938 }
939 catch(SSLException e)
940 {
941 LOG.warn(getRemoteAddr()+":"+getRemotePort()+" "+e);
942 super.close();
943 throw e;
944 }
945 finally
946 {
947 out_buffer.position(0);
948
949 if (consumed>0)
950 {
951 int len=consumed<buffer.length()?consumed:buffer.length();
952 buffer.skip(len);
953 consumed-=len;
954 _gather[0].position(0);
955 _gather[0].limit(_gather[0].capacity());
956 }
957 assert consumed==0;
958
959 freeOutBuffer();
960 }
961 }
962 }
963 switch(_result.getStatus())
964 {
965 case BUFFER_OVERFLOW:
966 case BUFFER_UNDERFLOW:
967 LOG.warn("unwrap {}",_result);
968
969 case OK:
970 return _result.bytesConsumed();
971 case CLOSED:
972 _closing=true;
973 return _result.bytesConsumed()>0?_result.bytesConsumed():-1;
974
975 default:
976 LOG.warn("wrap "+_result);
977 throw new IOException(_result.toString());
978 }
979 }
980
981
982 @Override
983 public boolean isBufferingInput()
984 {
985 final Buffer in = _inNIOBuffer;
986 return in==null?false:_inNIOBuffer.hasContent();
987 }
988
989
990 @Override
991 public boolean isBufferingOutput()
992 {
993 final NIOBuffer b=_outNIOBuffer;
994 return b==null?false:b.hasContent();
995 }
996
997
998 @Override
999 public boolean isBufferred()
1000 {
1001 return true;
1002 }
1003
1004
1005 public SSLEngine getSSLEngine()
1006 {
1007 return _engine;
1008 }
1009
1010
1011 @Override
1012 public void scheduleWrite()
1013 {
1014
1015 if (!HandshakeStatus.NEED_UNWRAP.equals(_engine.getHandshakeStatus()) || super.isBufferingOutput())
1016 super.scheduleWrite();
1017 }
1018
1019
1020 @Override
1021 public String toString()
1022 {
1023 final NIOBuffer i=_inNIOBuffer;
1024 final NIOBuffer o=_outNIOBuffer;
1025 return "SSL"+super.toString()+","+_engine.getHandshakeStatus()+", in/out="+
1026 (i==null?0:_inNIOBuffer.length())+"/"+(o==null?0:o.length())+
1027 " bi/o="+isBufferingInput()+"/"+isBufferingOutput()+
1028 " "+_result;
1029 }
1030 }