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