comparison src/org/eclipse/jetty/io/nio/SslConnection.java @ 940:b77d631b9e28

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