Mercurial Hosting > luan
comparison src/org/eclipse/jetty/io/nio/SslConnection.java @ 802:3428c60d7cfc
replace jetty jars with source
| author | Franklin Schmidt <fschmidt@gmail.com> |
|---|---|
| date | Wed, 07 Sep 2016 21:15:48 -0600 |
| parents | |
| children | 8e9db0bbf4f9 |
comparison
equal
deleted
inserted
replaced
| 801:6a21393191c1 | 802:3428c60d7cfc |
|---|---|
| 1 // | |
| 2 // ======================================================================== | |
| 3 // Copyright (c) 1995-2014 Mort Bay Consulting Pty. Ltd. | |
| 4 // ------------------------------------------------------------------------ | |
| 5 // All rights reserved. This program and the accompanying materials | |
| 6 // are made available under the terms of the Eclipse Public License v1.0 | |
| 7 // and Apache License v2.0 which accompanies this distribution. | |
| 8 // | |
| 9 // The Eclipse Public License is available at | |
| 10 // http://www.eclipse.org/legal/epl-v10.html | |
| 11 // | |
| 12 // The Apache License v2.0 is available at | |
| 13 // http://www.opensource.org/licenses/apache2.0.php | |
| 14 // | |
| 15 // You may elect to redistribute this code under either of these licenses. | |
| 16 // ======================================================================== | |
| 17 // | |
| 18 | |
| 19 package org.eclipse.jetty.io.nio; | |
| 20 | |
| 21 import java.io.IOException; | |
| 22 import java.nio.ByteBuffer; | |
| 23 import java.util.concurrent.atomic.AtomicBoolean; | |
| 24 import javax.net.ssl.SSLEngine; | |
| 25 import javax.net.ssl.SSLEngineResult; | |
| 26 import javax.net.ssl.SSLEngineResult.HandshakeStatus; | |
| 27 import javax.net.ssl.SSLException; | |
| 28 import javax.net.ssl.SSLSession; | |
| 29 | |
| 30 import org.eclipse.jetty.io.AbstractConnection; | |
| 31 import org.eclipse.jetty.io.AsyncEndPoint; | |
| 32 import org.eclipse.jetty.io.Buffer; | |
| 33 import org.eclipse.jetty.io.Connection; | |
| 34 import org.eclipse.jetty.io.EndPoint; | |
| 35 import org.eclipse.jetty.util.log.Log; | |
| 36 import org.eclipse.jetty.util.log.Logger; | |
| 37 import org.eclipse.jetty.util.thread.Timeout.Task; | |
| 38 | |
| 39 /* ------------------------------------------------------------ */ | |
| 40 /** SSL Connection. | |
| 41 * An AysyncConnection that acts as an interceptor between and EndPoint and another | |
| 42 * Connection, that implements TLS encryption using an {@link SSLEngine}. | |
| 43 * <p> | |
| 44 * The connector uses an {@link AsyncEndPoint} (like {@link SelectChannelEndPoint}) as | |
| 45 * it's source/sink of encrypted data. It then provides {@link #getSslEndPoint()} to | |
| 46 * expose a source/sink of unencrypted data to another connection (eg HttpConnection). | |
| 47 */ | |
| 48 public class SslConnection extends AbstractConnection implements AsyncConnection | |
| 49 { | |
| 50 private final Logger _logger = Log.getLogger("org.eclipse.jetty.io.nio.ssl"); | |
| 51 | |
| 52 private static final NIOBuffer __ZERO_BUFFER=new IndirectNIOBuffer(0); | |
| 53 | |
| 54 private static final ThreadLocal<SslBuffers> __buffers = new ThreadLocal<SslBuffers>(); | |
| 55 private final SSLEngine _engine; | |
| 56 private final SSLSession _session; | |
| 57 private AsyncConnection _connection; | |
| 58 private final SslEndPoint _sslEndPoint; | |
| 59 private int _allocations; | |
| 60 private SslBuffers _buffers; | |
| 61 private NIOBuffer _inbound; | |
| 62 private NIOBuffer _unwrapBuf; | |
| 63 private NIOBuffer _outbound; | |
| 64 private AsyncEndPoint _aEndp; | |
| 65 private boolean _allowRenegotiate=true; | |
| 66 private boolean _handshook; | |
| 67 private boolean _ishut; | |
| 68 private boolean _oshut; | |
| 69 private final AtomicBoolean _progressed = new AtomicBoolean(); | |
| 70 | |
| 71 /* ------------------------------------------------------------ */ | |
| 72 /* this is a half baked buffer pool | |
| 73 */ | |
| 74 private static class SslBuffers | |
| 75 { | |
| 76 final NIOBuffer _in; | |
| 77 final NIOBuffer _out; | |
| 78 final NIOBuffer _unwrap; | |
| 79 | |
| 80 SslBuffers(int packetSize, int appSize) | |
| 81 { | |
| 82 _in=new IndirectNIOBuffer(packetSize); | |
| 83 _out=new IndirectNIOBuffer(packetSize); | |
| 84 _unwrap=new IndirectNIOBuffer(appSize); | |
| 85 } | |
| 86 } | |
| 87 | |
| 88 /* ------------------------------------------------------------ */ | |
| 89 public SslConnection(SSLEngine engine,EndPoint endp) | |
| 90 { | |
| 91 this(engine,endp,System.currentTimeMillis()); | |
| 92 } | |
| 93 | |
| 94 /* ------------------------------------------------------------ */ | |
| 95 public SslConnection(SSLEngine engine,EndPoint endp, long timeStamp) | |
| 96 { | |
| 97 super(endp,timeStamp); | |
| 98 _engine=engine; | |
| 99 _session=_engine.getSession(); | |
| 100 _aEndp=(AsyncEndPoint)endp; | |
| 101 _sslEndPoint = newSslEndPoint(); | |
| 102 } | |
| 103 | |
| 104 /* ------------------------------------------------------------ */ | |
| 105 protected SslEndPoint newSslEndPoint() | |
| 106 { | |
| 107 return new SslEndPoint(); | |
| 108 } | |
| 109 | |
| 110 /* ------------------------------------------------------------ */ | |
| 111 /** | |
| 112 * @return True if SSL re-negotiation is allowed (default false) | |
| 113 */ | |
| 114 public boolean isAllowRenegotiate() | |
| 115 { | |
| 116 return _allowRenegotiate; | |
| 117 } | |
| 118 | |
| 119 /* ------------------------------------------------------------ */ | |
| 120 /** | |
| 121 * Set if SSL re-negotiation is allowed. CVE-2009-3555 discovered | |
| 122 * a vulnerability in SSL/TLS with re-negotiation. If your JVM | |
| 123 * does not have CVE-2009-3555 fixed, then re-negotiation should | |
| 124 * not be allowed. CVE-2009-3555 was fixed in Sun java 1.6 with a ban | |
| 125 * of renegotiates in u19 and with RFC5746 in u22. | |
| 126 * | |
| 127 * @param allowRenegotiate | |
| 128 * true if re-negotiation is allowed (default false) | |
| 129 */ | |
| 130 public void setAllowRenegotiate(boolean allowRenegotiate) | |
| 131 { | |
| 132 _allowRenegotiate = allowRenegotiate; | |
| 133 } | |
| 134 | |
| 135 /* ------------------------------------------------------------ */ | |
| 136 private void allocateBuffers() | |
| 137 { | |
| 138 synchronized (this) | |
| 139 { | |
| 140 if (_allocations++==0) | |
| 141 { | |
| 142 if (_buffers==null) | |
| 143 { | |
| 144 _buffers=__buffers.get(); | |
| 145 if (_buffers==null) | |
| 146 _buffers=new SslBuffers(_session.getPacketBufferSize()*2,_session.getApplicationBufferSize()*2); | |
| 147 _inbound=_buffers._in; | |
| 148 _outbound=_buffers._out; | |
| 149 _unwrapBuf=_buffers._unwrap; | |
| 150 __buffers.set(null); | |
| 151 } | |
| 152 } | |
| 153 } | |
| 154 } | |
| 155 | |
| 156 /* ------------------------------------------------------------ */ | |
| 157 private void releaseBuffers() | |
| 158 { | |
| 159 synchronized (this) | |
| 160 { | |
| 161 if (--_allocations==0) | |
| 162 { | |
| 163 if (_buffers!=null && | |
| 164 _inbound.length()==0 && | |
| 165 _outbound.length()==0 && | |
| 166 _unwrapBuf.length()==0) | |
| 167 { | |
| 168 _inbound=null; | |
| 169 _outbound=null; | |
| 170 _unwrapBuf=null; | |
| 171 __buffers.set(_buffers); | |
| 172 _buffers=null; | |
| 173 } | |
| 174 } | |
| 175 } | |
| 176 } | |
| 177 | |
| 178 /* ------------------------------------------------------------ */ | |
| 179 public Connection handle() throws IOException | |
| 180 { | |
| 181 try | |
| 182 { | |
| 183 allocateBuffers(); | |
| 184 | |
| 185 boolean progress=true; | |
| 186 | |
| 187 while (progress) | |
| 188 { | |
| 189 progress=false; | |
| 190 | |
| 191 // If we are handshook let the delegate connection | |
| 192 if (_engine.getHandshakeStatus()!=HandshakeStatus.NOT_HANDSHAKING) | |
| 193 progress=process(null,null); | |
| 194 | |
| 195 // handle the delegate connection | |
| 196 AsyncConnection next = (AsyncConnection)_connection.handle(); | |
| 197 if (next!=_connection && next!=null) | |
| 198 { | |
| 199 _connection=next; | |
| 200 progress=true; | |
| 201 } | |
| 202 | |
| 203 _logger.debug("{} handle {} progress={}", _session, this, progress); | |
| 204 } | |
| 205 } | |
| 206 finally | |
| 207 { | |
| 208 releaseBuffers(); | |
| 209 | |
| 210 if (!_ishut && _sslEndPoint.isInputShutdown() && _sslEndPoint.isOpen()) | |
| 211 { | |
| 212 _ishut=true; | |
| 213 try | |
| 214 { | |
| 215 _connection.onInputShutdown(); | |
| 216 } | |
| 217 catch(Throwable x) | |
| 218 { | |
| 219 _logger.warn("onInputShutdown failed", x); | |
| 220 try{_sslEndPoint.close();} | |
| 221 catch(IOException e2){ | |
| 222 _logger.ignore(e2);} | |
| 223 } | |
| 224 } | |
| 225 } | |
| 226 | |
| 227 return this; | |
| 228 } | |
| 229 | |
| 230 /* ------------------------------------------------------------ */ | |
| 231 public boolean isIdle() | |
| 232 { | |
| 233 return false; | |
| 234 } | |
| 235 | |
| 236 /* ------------------------------------------------------------ */ | |
| 237 public boolean isSuspended() | |
| 238 { | |
| 239 return false; | |
| 240 } | |
| 241 | |
| 242 /* ------------------------------------------------------------ */ | |
| 243 public void onClose() | |
| 244 { | |
| 245 Connection connection = _sslEndPoint.getConnection(); | |
| 246 if (connection != null && connection != this) | |
| 247 connection.onClose(); | |
| 248 } | |
| 249 | |
| 250 /* ------------------------------------------------------------ */ | |
| 251 @Override | |
| 252 public void onIdleExpired(long idleForMs) | |
| 253 { | |
| 254 try | |
| 255 { | |
| 256 _logger.debug("onIdleExpired {}ms on {}",idleForMs,this); | |
| 257 if (_endp.isOutputShutdown()) | |
| 258 _sslEndPoint.close(); | |
| 259 else | |
| 260 _sslEndPoint.shutdownOutput(); | |
| 261 } | |
| 262 catch (IOException e) | |
| 263 { | |
| 264 _logger.warn(e); | |
| 265 super.onIdleExpired(idleForMs); | |
| 266 } | |
| 267 } | |
| 268 | |
| 269 /* ------------------------------------------------------------ */ | |
| 270 public void onInputShutdown() throws IOException | |
| 271 { | |
| 272 | |
| 273 } | |
| 274 | |
| 275 /* ------------------------------------------------------------ */ | |
| 276 private synchronized boolean process(Buffer toFill, Buffer toFlush) throws IOException | |
| 277 { | |
| 278 boolean some_progress=false; | |
| 279 try | |
| 280 { | |
| 281 // We need buffers to progress | |
| 282 allocateBuffers(); | |
| 283 | |
| 284 // if we don't have a buffer to put received data into | |
| 285 if (toFill==null) | |
| 286 { | |
| 287 // use the unwrapbuffer to hold received data. | |
| 288 _unwrapBuf.compact(); | |
| 289 toFill=_unwrapBuf; | |
| 290 } | |
| 291 // Else if the fill buffer is too small for the SSL session | |
| 292 else if (toFill.capacity()<_session.getApplicationBufferSize()) | |
| 293 { | |
| 294 // fill to the temporary unwrapBuffer | |
| 295 boolean progress=process(null,toFlush); | |
| 296 | |
| 297 // if we received any data, | |
| 298 if (_unwrapBuf!=null && _unwrapBuf.hasContent()) | |
| 299 { | |
| 300 // transfer from temp buffer to fill buffer | |
| 301 _unwrapBuf.skip(toFill.put(_unwrapBuf)); | |
| 302 return true; | |
| 303 } | |
| 304 else | |
| 305 // return progress from recursive call | |
| 306 return progress; | |
| 307 } | |
| 308 // Else if there is some temporary data | |
| 309 else if (_unwrapBuf!=null && _unwrapBuf.hasContent()) | |
| 310 { | |
| 311 // transfer from temp buffer to fill buffer | |
| 312 _unwrapBuf.skip(toFill.put(_unwrapBuf)); | |
| 313 return true; | |
| 314 } | |
| 315 | |
| 316 // If we are here, we have a buffer ready into which we can put some read data. | |
| 317 | |
| 318 // If we have no data to flush, flush the empty buffer | |
| 319 if (toFlush==null) | |
| 320 toFlush=__ZERO_BUFFER; | |
| 321 | |
| 322 // While we are making progress processing SSL engine | |
| 323 boolean progress=true; | |
| 324 while (progress) | |
| 325 { | |
| 326 progress=false; | |
| 327 | |
| 328 // Do any real IO | |
| 329 int filled=0,flushed=0; | |
| 330 try | |
| 331 { | |
| 332 // Read any available data | |
| 333 if (_inbound.space()>0 && (filled=_endp.fill(_inbound))>0) | |
| 334 progress = true; | |
| 335 | |
| 336 // flush any output data | |
| 337 if (_outbound.hasContent() && (flushed=_endp.flush(_outbound))>0) | |
| 338 progress = true; | |
| 339 } | |
| 340 catch (IOException e) | |
| 341 { | |
| 342 _endp.close(); | |
| 343 throw e; | |
| 344 } | |
| 345 finally | |
| 346 { | |
| 347 _logger.debug("{} {} {} filled={}/{} flushed={}/{}",_session,this,_engine.getHandshakeStatus(),filled,_inbound.length(),flushed,_outbound.length()); | |
| 348 } | |
| 349 | |
| 350 // handle the current hand share status | |
| 351 switch(_engine.getHandshakeStatus()) | |
| 352 { | |
| 353 case FINISHED: | |
| 354 throw new IllegalStateException(); | |
| 355 | |
| 356 case NOT_HANDSHAKING: | |
| 357 { | |
| 358 // Try unwrapping some application data | |
| 359 if (toFill.space()>0 && _inbound.hasContent() && unwrap(toFill)) | |
| 360 progress=true; | |
| 361 | |
| 362 // Try wrapping some application data | |
| 363 if (toFlush.hasContent() && _outbound.space()>0 && wrap(toFlush)) | |
| 364 progress=true; | |
| 365 } | |
| 366 break; | |
| 367 | |
| 368 case NEED_TASK: | |
| 369 { | |
| 370 // A task needs to be run, so run it! | |
| 371 Runnable task; | |
| 372 while ((task=_engine.getDelegatedTask())!=null) | |
| 373 { | |
| 374 progress=true; | |
| 375 task.run(); | |
| 376 } | |
| 377 | |
| 378 } | |
| 379 break; | |
| 380 | |
| 381 case NEED_WRAP: | |
| 382 { | |
| 383 // The SSL needs to send some handshake data to the other side | |
| 384 if (_handshook && !_allowRenegotiate) | |
| 385 _endp.close(); | |
| 386 else if (wrap(toFlush)) | |
| 387 progress=true; | |
| 388 } | |
| 389 break; | |
| 390 | |
| 391 case NEED_UNWRAP: | |
| 392 { | |
| 393 // The SSL needs to receive some handshake data from the other side | |
| 394 if (_handshook && !_allowRenegotiate) | |
| 395 _endp.close(); | |
| 396 else if (!_inbound.hasContent()&&filled==-1) | |
| 397 { | |
| 398 // No more input coming | |
| 399 _endp.shutdownInput(); | |
| 400 } | |
| 401 else if (unwrap(toFill)) | |
| 402 progress=true; | |
| 403 } | |
| 404 break; | |
| 405 } | |
| 406 | |
| 407 // pass on ishut/oshut state | |
| 408 if (_endp.isOpen() && _endp.isInputShutdown() && !_inbound.hasContent()) | |
| 409 closeInbound(); | |
| 410 | |
| 411 if (_endp.isOpen() && _engine.isOutboundDone() && !_outbound.hasContent()) | |
| 412 _endp.shutdownOutput(); | |
| 413 | |
| 414 // remember if any progress has been made | |
| 415 some_progress|=progress; | |
| 416 } | |
| 417 | |
| 418 // If we are reading into the temp buffer and it has some content, then we should be dispatched. | |
| 419 if (toFill==_unwrapBuf && _unwrapBuf.hasContent() && !_connection.isSuspended()) | |
| 420 _aEndp.dispatch(); | |
| 421 } | |
| 422 finally | |
| 423 { | |
| 424 releaseBuffers(); | |
| 425 if (some_progress) | |
| 426 _progressed.set(true); | |
| 427 } | |
| 428 return some_progress; | |
| 429 } | |
| 430 | |
| 431 private void closeInbound() | |
| 432 { | |
| 433 try | |
| 434 { | |
| 435 _engine.closeInbound(); | |
| 436 } | |
| 437 catch (SSLException x) | |
| 438 { | |
| 439 _logger.debug(x); | |
| 440 } | |
| 441 } | |
| 442 | |
| 443 private synchronized boolean wrap(final Buffer buffer) throws IOException | |
| 444 { | |
| 445 ByteBuffer bbuf=extractByteBuffer(buffer); | |
| 446 final SSLEngineResult result; | |
| 447 | |
| 448 synchronized(bbuf) | |
| 449 { | |
| 450 _outbound.compact(); | |
| 451 ByteBuffer out_buffer=_outbound.getByteBuffer(); | |
| 452 synchronized(out_buffer) | |
| 453 { | |
| 454 try | |
| 455 { | |
| 456 bbuf.position(buffer.getIndex()); | |
| 457 bbuf.limit(buffer.putIndex()); | |
| 458 out_buffer.position(_outbound.putIndex()); | |
| 459 out_buffer.limit(out_buffer.capacity()); | |
| 460 result=_engine.wrap(bbuf,out_buffer); | |
| 461 if (_logger.isDebugEnabled()) | |
| 462 _logger.debug("{} wrap {} {} consumed={} produced={}", | |
| 463 _session, | |
| 464 result.getStatus(), | |
| 465 result.getHandshakeStatus(), | |
| 466 result.bytesConsumed(), | |
| 467 result.bytesProduced()); | |
| 468 | |
| 469 | |
| 470 buffer.skip(result.bytesConsumed()); | |
| 471 _outbound.setPutIndex(_outbound.putIndex()+result.bytesProduced()); | |
| 472 } | |
| 473 catch(SSLException e) | |
| 474 { | |
| 475 _logger.debug(String.valueOf(_endp), e); | |
| 476 _endp.close(); | |
| 477 throw e; | |
| 478 } | |
| 479 finally | |
| 480 { | |
| 481 out_buffer.position(0); | |
| 482 out_buffer.limit(out_buffer.capacity()); | |
| 483 bbuf.position(0); | |
| 484 bbuf.limit(bbuf.capacity()); | |
| 485 } | |
| 486 } | |
| 487 } | |
| 488 | |
| 489 switch(result.getStatus()) | |
| 490 { | |
| 491 case BUFFER_UNDERFLOW: | |
| 492 throw new IllegalStateException(); | |
| 493 | |
| 494 case BUFFER_OVERFLOW: | |
| 495 break; | |
| 496 | |
| 497 case OK: | |
| 498 if (result.getHandshakeStatus()==HandshakeStatus.FINISHED) | |
| 499 _handshook=true; | |
| 500 break; | |
| 501 | |
| 502 case CLOSED: | |
| 503 _logger.debug("wrap CLOSE {} {}",this,result); | |
| 504 if (result.getHandshakeStatus()==HandshakeStatus.FINISHED) | |
| 505 _endp.close(); | |
| 506 break; | |
| 507 | |
| 508 default: | |
| 509 _logger.debug("{} wrap default {}",_session,result); | |
| 510 throw new IOException(result.toString()); | |
| 511 } | |
| 512 | |
| 513 return result.bytesConsumed()>0 || result.bytesProduced()>0; | |
| 514 } | |
| 515 | |
| 516 private synchronized boolean unwrap(final Buffer buffer) throws IOException | |
| 517 { | |
| 518 if (!_inbound.hasContent()) | |
| 519 return false; | |
| 520 | |
| 521 ByteBuffer bbuf=extractByteBuffer(buffer); | |
| 522 final SSLEngineResult result; | |
| 523 | |
| 524 synchronized(bbuf) | |
| 525 { | |
| 526 ByteBuffer in_buffer=_inbound.getByteBuffer(); | |
| 527 synchronized(in_buffer) | |
| 528 { | |
| 529 try | |
| 530 { | |
| 531 bbuf.position(buffer.putIndex()); | |
| 532 bbuf.limit(buffer.capacity()); | |
| 533 in_buffer.position(_inbound.getIndex()); | |
| 534 in_buffer.limit(_inbound.putIndex()); | |
| 535 | |
| 536 result=_engine.unwrap(in_buffer,bbuf); | |
| 537 if (_logger.isDebugEnabled()) | |
| 538 _logger.debug("{} unwrap {} {} consumed={} produced={}", | |
| 539 _session, | |
| 540 result.getStatus(), | |
| 541 result.getHandshakeStatus(), | |
| 542 result.bytesConsumed(), | |
| 543 result.bytesProduced()); | |
| 544 | |
| 545 _inbound.skip(result.bytesConsumed()); | |
| 546 _inbound.compact(); | |
| 547 buffer.setPutIndex(buffer.putIndex()+result.bytesProduced()); | |
| 548 } | |
| 549 catch(SSLException e) | |
| 550 { | |
| 551 _logger.debug(String.valueOf(_endp), e); | |
| 552 _endp.close(); | |
| 553 throw e; | |
| 554 } | |
| 555 finally | |
| 556 { | |
| 557 in_buffer.position(0); | |
| 558 in_buffer.limit(in_buffer.capacity()); | |
| 559 bbuf.position(0); | |
| 560 bbuf.limit(bbuf.capacity()); | |
| 561 } | |
| 562 } | |
| 563 } | |
| 564 | |
| 565 switch(result.getStatus()) | |
| 566 { | |
| 567 case BUFFER_UNDERFLOW: | |
| 568 if (_endp.isInputShutdown()) | |
| 569 _inbound.clear(); | |
| 570 break; | |
| 571 | |
| 572 case BUFFER_OVERFLOW: | |
| 573 if (_logger.isDebugEnabled()) _logger.debug("{} unwrap {} {}->{}",_session,result.getStatus(),_inbound.toDetailString(),buffer.toDetailString()); | |
| 574 break; | |
| 575 | |
| 576 case OK: | |
| 577 if (result.getHandshakeStatus()==HandshakeStatus.FINISHED) | |
| 578 _handshook=true; | |
| 579 break; | |
| 580 | |
| 581 case CLOSED: | |
| 582 _logger.debug("unwrap CLOSE {} {}",this,result); | |
| 583 if (result.getHandshakeStatus()==HandshakeStatus.FINISHED) | |
| 584 _endp.close(); | |
| 585 break; | |
| 586 | |
| 587 default: | |
| 588 _logger.debug("{} wrap default {}",_session,result); | |
| 589 throw new IOException(result.toString()); | |
| 590 } | |
| 591 | |
| 592 //if (LOG.isDebugEnabled() && result.bytesProduced()>0) | |
| 593 // LOG.debug("{} unwrapped '{}'",_session,buffer); | |
| 594 | |
| 595 return result.bytesConsumed()>0 || result.bytesProduced()>0; | |
| 596 } | |
| 597 | |
| 598 | |
| 599 /* ------------------------------------------------------------ */ | |
| 600 private ByteBuffer extractByteBuffer(Buffer buffer) | |
| 601 { | |
| 602 if (buffer.buffer() instanceof NIOBuffer) | |
| 603 return ((NIOBuffer)buffer.buffer()).getByteBuffer(); | |
| 604 return ByteBuffer.wrap(buffer.array()); | |
| 605 } | |
| 606 | |
| 607 /* ------------------------------------------------------------ */ | |
| 608 public AsyncEndPoint getSslEndPoint() | |
| 609 { | |
| 610 return _sslEndPoint; | |
| 611 } | |
| 612 | |
| 613 /* ------------------------------------------------------------ */ | |
| 614 public String toString() | |
| 615 { | |
| 616 return String.format("%s %s", super.toString(), _sslEndPoint); | |
| 617 } | |
| 618 | |
| 619 /* ------------------------------------------------------------ */ | |
| 620 /* ------------------------------------------------------------ */ | |
| 621 public class SslEndPoint implements AsyncEndPoint | |
| 622 { | |
| 623 public SSLEngine getSslEngine() | |
| 624 { | |
| 625 return _engine; | |
| 626 } | |
| 627 | |
| 628 public AsyncEndPoint getEndpoint() | |
| 629 { | |
| 630 return _aEndp; | |
| 631 } | |
| 632 | |
| 633 public void shutdownOutput() throws IOException | |
| 634 { | |
| 635 synchronized (SslConnection.this) | |
| 636 { | |
| 637 _logger.debug("{} ssl endp.oshut {}",_session,this); | |
| 638 _engine.closeOutbound(); | |
| 639 _oshut=true; | |
| 640 } | |
| 641 flush(); | |
| 642 } | |
| 643 | |
| 644 public boolean isOutputShutdown() | |
| 645 { | |
| 646 synchronized (SslConnection.this) | |
| 647 { | |
| 648 return _oshut||!isOpen()||_engine.isOutboundDone(); | |
| 649 } | |
| 650 } | |
| 651 | |
| 652 public void shutdownInput() throws IOException | |
| 653 { | |
| 654 _logger.debug("{} ssl endp.ishut!",_session); | |
| 655 // We do not do a closeInput here, as SSL does not support half close. | |
| 656 // isInputShutdown works it out itself from buffer state and underlying endpoint state. | |
| 657 } | |
| 658 | |
| 659 public boolean isInputShutdown() | |
| 660 { | |
| 661 synchronized (SslConnection.this) | |
| 662 { | |
| 663 return _endp.isInputShutdown() && | |
| 664 !(_unwrapBuf!=null&&_unwrapBuf.hasContent()) && | |
| 665 !(_inbound!=null&&_inbound.hasContent()); | |
| 666 } | |
| 667 } | |
| 668 | |
| 669 public void close() throws IOException | |
| 670 { | |
| 671 _logger.debug("{} ssl endp.close",_session); | |
| 672 _endp.close(); | |
| 673 } | |
| 674 | |
| 675 public int fill(Buffer buffer) throws IOException | |
| 676 { | |
| 677 int size=buffer.length(); | |
| 678 process(buffer, null); | |
| 679 | |
| 680 int filled=buffer.length()-size; | |
| 681 | |
| 682 if (filled==0 && isInputShutdown()) | |
| 683 return -1; | |
| 684 return filled; | |
| 685 } | |
| 686 | |
| 687 public int flush(Buffer buffer) throws IOException | |
| 688 { | |
| 689 int size = buffer.length(); | |
| 690 process(null, buffer); | |
| 691 return size-buffer.length(); | |
| 692 } | |
| 693 | |
| 694 public int flush(Buffer header, Buffer buffer, Buffer trailer) throws IOException | |
| 695 { | |
| 696 if (header!=null && header.hasContent()) | |
| 697 return flush(header); | |
| 698 if (buffer!=null && buffer.hasContent()) | |
| 699 return flush(buffer); | |
| 700 if (trailer!=null && trailer.hasContent()) | |
| 701 return flush(trailer); | |
| 702 return 0; | |
| 703 } | |
| 704 | |
| 705 public boolean blockReadable(long millisecs) throws IOException | |
| 706 { | |
| 707 long now = System.currentTimeMillis(); | |
| 708 long end=millisecs>0?(now+millisecs):Long.MAX_VALUE; | |
| 709 | |
| 710 while (now<end) | |
| 711 { | |
| 712 if (process(null,null)) | |
| 713 break; | |
| 714 _endp.blockReadable(end-now); | |
| 715 now = System.currentTimeMillis(); | |
| 716 } | |
| 717 | |
| 718 return now<end; | |
| 719 } | |
| 720 | |
| 721 public boolean blockWritable(long millisecs) throws IOException | |
| 722 { | |
| 723 return _endp.blockWritable(millisecs); | |
| 724 } | |
| 725 | |
| 726 public boolean isOpen() | |
| 727 { | |
| 728 return _endp.isOpen(); | |
| 729 } | |
| 730 | |
| 731 public Object getTransport() | |
| 732 { | |
| 733 return _endp; | |
| 734 } | |
| 735 | |
| 736 public void flush() throws IOException | |
| 737 { | |
| 738 process(null, null); | |
| 739 } | |
| 740 | |
| 741 public void dispatch() | |
| 742 { | |
| 743 _aEndp.dispatch(); | |
| 744 } | |
| 745 | |
| 746 public void asyncDispatch() | |
| 747 { | |
| 748 _aEndp.asyncDispatch(); | |
| 749 } | |
| 750 | |
| 751 public void scheduleWrite() | |
| 752 { | |
| 753 _aEndp.scheduleWrite(); | |
| 754 } | |
| 755 | |
| 756 public void onIdleExpired(long idleForMs) | |
| 757 { | |
| 758 _aEndp.onIdleExpired(idleForMs); | |
| 759 } | |
| 760 | |
| 761 public void setCheckForIdle(boolean check) | |
| 762 { | |
| 763 _aEndp.setCheckForIdle(check); | |
| 764 } | |
| 765 | |
| 766 public boolean isCheckForIdle() | |
| 767 { | |
| 768 return _aEndp.isCheckForIdle(); | |
| 769 } | |
| 770 | |
| 771 public void scheduleTimeout(Task task, long timeoutMs) | |
| 772 { | |
| 773 _aEndp.scheduleTimeout(task,timeoutMs); | |
| 774 } | |
| 775 | |
| 776 public void cancelTimeout(Task task) | |
| 777 { | |
| 778 _aEndp.cancelTimeout(task); | |
| 779 } | |
| 780 | |
| 781 public boolean isWritable() | |
| 782 { | |
| 783 return _aEndp.isWritable(); | |
| 784 } | |
| 785 | |
| 786 public boolean hasProgressed() | |
| 787 { | |
| 788 return _progressed.getAndSet(false); | |
| 789 } | |
| 790 | |
| 791 public String getLocalAddr() | |
| 792 { | |
| 793 return _aEndp.getLocalAddr(); | |
| 794 } | |
| 795 | |
| 796 public String getLocalHost() | |
| 797 { | |
| 798 return _aEndp.getLocalHost(); | |
| 799 } | |
| 800 | |
| 801 public int getLocalPort() | |
| 802 { | |
| 803 return _aEndp.getLocalPort(); | |
| 804 } | |
| 805 | |
| 806 public String getRemoteAddr() | |
| 807 { | |
| 808 return _aEndp.getRemoteAddr(); | |
| 809 } | |
| 810 | |
| 811 public String getRemoteHost() | |
| 812 { | |
| 813 return _aEndp.getRemoteHost(); | |
| 814 } | |
| 815 | |
| 816 public int getRemotePort() | |
| 817 { | |
| 818 return _aEndp.getRemotePort(); | |
| 819 } | |
| 820 | |
| 821 public boolean isBlocking() | |
| 822 { | |
| 823 return false; | |
| 824 } | |
| 825 | |
| 826 public int getMaxIdleTime() | |
| 827 { | |
| 828 return _aEndp.getMaxIdleTime(); | |
| 829 } | |
| 830 | |
| 831 public void setMaxIdleTime(int timeMs) throws IOException | |
| 832 { | |
| 833 _aEndp.setMaxIdleTime(timeMs); | |
| 834 } | |
| 835 | |
| 836 public Connection getConnection() | |
| 837 { | |
| 838 return _connection; | |
| 839 } | |
| 840 | |
| 841 public void setConnection(Connection connection) | |
| 842 { | |
| 843 _connection=(AsyncConnection)connection; | |
| 844 } | |
| 845 | |
| 846 public String toString() | |
| 847 { | |
| 848 // Do NOT use synchronized (SslConnection.this) | |
| 849 // because it's very easy to deadlock when debugging is enabled. | |
| 850 // We do a best effort to print the right toString() and that's it. | |
| 851 Buffer inbound = _inbound; | |
| 852 Buffer outbound = _outbound; | |
| 853 Buffer unwrap = _unwrapBuf; | |
| 854 int i = inbound == null? -1 : inbound.length(); | |
| 855 int o = outbound == null ? -1 : outbound.length(); | |
| 856 int u = unwrap == null ? -1 : unwrap.length(); | |
| 857 return String.format("SSL %s i/o/u=%d/%d/%d ishut=%b oshut=%b {%s}", | |
| 858 _engine.getHandshakeStatus(), | |
| 859 i, o, u, | |
| 860 _ishut, _oshut, | |
| 861 _connection); | |
| 862 } | |
| 863 | |
| 864 } | |
| 865 } |
