##### Coverage Report - com.sun.grizzly.SSLConnectorHandler

Classes in this File | Line Coverage | Branch Coverage | Complexity
SSLConnectorHandler |
76 % | 228/299
67 % | 95/142
| 0.0;0
SSLConnectorHandler$1 |
43 % | 3/7
0 % | 0/2
| 0.0;0
SSLConnectorHandler$2 |
100 % | 2/2
N/A | N/A
| 0.0;0
SSLConnectorHandler$SSLInternalCallbackHandler |
54 % | 13/24
38 % | 6/16
| 0.0;0
SSLConnectorHandler$SSLReadPostProcessor |
100 % | 6/6
N/A | N/A
| 0.0;0
SSLConnectorHandler$SSLWritePreProcessor |
100 % | 8/8
50 % | 2/4
| 0.0;0

1 |  |
     /*
2 |  |
      *
3 |  |
      * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4 |  |
      *
5 |  |
      * Copyright 2007-2008 Sun Microsystems, Inc. All rights reserved.
6 |  |
      *
7 |  |
      * The contents of this file are subject to the terms of either the GNU
8 |  |
      * General Public License Version 2 only ("GPL") or the Common Development
9 |  |
      * and Distribution License("CDDL") (collectively, the "License").  You
10 |  |
      * may not use this file except in compliance with the License. You can obtain
11 |  |
      * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
12 |  |
      * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
13 |  |
      * language governing permissions and limitations under the License.
14 |  |
      *
15 |  |
      * When distributing the software, include this License Header Notice in each
16 |  |
      * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
17 |  |
      * Sun designates this particular file as subject to the "Classpath" exception
18 |  |
      * as provided by Sun in the GPL Version 2 section of the License file that
19 |  |
      * accompanied this code.  If applicable, add the following below the License
20 |  |
      * Header, with the fields enclosed by brackets [] replaced by your own
21 |  |
      * identifying information: "Portions Copyrighted [year]
22 |  |
      * [name of copyright owner]"
23 |  |
      *
24 |  |
      * Contributor(s):
25 |  |
      *
26 |  |
      * If you wish your version of this file to be governed by only the CDDL or
27 |  |
      * only the GPL Version 2, indicate your decision by adding "[Contributor]
28 |  |
      * elects to include this software in this distribution under the [CDDL or GPL
29 |  |
      * Version 2] license."  If you don't indicate a single choice of license, a
30 |  |
      * recipient has the option to distribute your version of this file under
31 |  |
      * either the CDDL, the GPL Version 2 or to extend the choice of license to
32 |  |
      * its licensees as provided above.  However, if you add GPL Version 2 code
33 |  |
      * and therefore, elected the GPL Version 2 license, then the option applies
34 |  |
      * only if the new code is made subject to such option by the copyright
35 |  |
      * holder.
36 |  |
      *
37 |  |
      */
38 |  |
     package com.sun.grizzly;
39 |  |
40 |  |
     import com.sun.grizzly.async.AsyncQueueDataProcessor;
41 |  |
     import com.sun.grizzly.async.AsyncQueueReadable;
42 |  |
     import com.sun.grizzly.async.AsyncQueueWritable;
43 |  |
     import com.sun.grizzly.async.AsyncReadCallbackHandler;
44 |  |
     import com.sun.grizzly.async.AsyncReadCondition;
45 |  |
     import com.sun.grizzly.async.AsyncWriteCallbackHandler;
46 |  |
     import com.sun.grizzly.util.OutputWriter;
47 |  |
     import com.sun.grizzly.util.SSLOutputWriter;
48 |  |
     import com.sun.grizzly.util.SSLUtils;
49 |  |
     import java.io.EOFException;
50 |  |
     import java.io.IOException;
51 |  |
     import java.net.SocketAddress;
52 |  |
     import java.nio.BufferOverflowException;
53 |  |
     import java.nio.ByteBuffer;
54 |  |
     import java.nio.channels.AlreadyConnectedException;
55 |  |
     import java.nio.channels.NotYetConnectedException;
56 |  |
     import java.nio.channels.SelectableChannel;
57 |  |
     import java.nio.channels.SelectionKey;
58 |  |
     import java.nio.channels.SocketChannel;
59 |  |
     import java.util.concurrent.CountDownLatch;
60 |  |
     import java.util.concurrent.TimeUnit;
61 |  |
     import java.util.logging.Level;
62 |  |
     import java.util.logging.Logger;
63 |  |
     import javax.net.ssl.SSLContext;
64 |  |
     import javax.net.ssl.SSLEngine;
65 |  |
     import javax.net.ssl.SSLEngineResult;
66 |  |
     import javax.net.ssl.SSLEngineResult.HandshakeStatus;
67 |  |
     import javax.net.ssl.SSLException;
68 |  |
69 |  |
     /**
70 |  |
      * <p>
71 |  |
      * Non blocking SSL Connector Handler. The recommended way to use this class
72 |  |
      * is by creating an external Controller and share the same SelectorHandler
73 |  |
      * instance.
74 |  |
      * </p><p>
75 |  |
      * Recommended
76 |  |
      * -----------
77 |  |
      * </p><p><pre><code>
78 |  |
      * Controller controller = new Controller();
79 |  |
      * // new SSLSelectorHandler(true) means the Selector will be used only
80 |  |
      * // for client operation (OP_READ, OP_WRITE, OP_CONNECT).
81 |  |
      * SSLSelectorHandler sslSelectorHandler = new SSLSelectorHandler(true);
82 |  |
      * controller.setSelectorHandler(sslSelectorHandler);
83 |  |
      * SSLConnectorHandler sslConnectorHandler = new SSLConnectorHandler();
84 |  |
      * sslConnectorHandler.connect(localhost,port, new SSLCallbackHandler(){...},
85 |  |
      *                             sslSelectorHandler);
86 |  |
      * SSLConnectorHandler sslConnectorHandler2 = new SSLConnectorHandler();
87 |  |
      * sslConnectorHandler2.connect(localhost,port, new SSLCallbackHandler(){...},
88 |  |
      *                             sslSelectorHandler);
89 |  |
      * </code></pre></p><p>
90 |  |
      * Not recommended (but still works)
91 |  |
      * ---------------------------------
92 |  |
      * </p><p><pre><code>
93 |  |
      * SSLConnectorHandler sslConnectorHandler = new SSLConnectorHandler();
94 |  |
      * sslConnectorHandler.connect(localhost,port);
95 |  |
      *
96 |  |
      * Internally, an new Controller will be created everytime connect(localhost,port)
97 |  |
      * is invoked, which has an impact on performance.
98 |  |
      *
99 |  |
      * As common comment: developer should be very careful if dealing directly with
100 |  |
      * <code>SSLConnectorHandler</code>'s underlying socket channel! In most cases
101 |  |
      * there is no need to do this, but use read, write methods provided
102 |  |
      * by <code>SSLConnectorHandler</code>
103 |  |
      * </code></pre></p>
104 |  |
      *
105 |  |
      * @author Alexey Stashok
106 |  |
      * @author Jeanfrancois Arcand
107 |  |
      */
108 | 5106430 |
     public class SSLConnectorHandler implements ConnectorHandler<SSLSelectorHandler,
109 |  |
             SSLCallbackHandler>, AsyncQueueWritable, AsyncQueueReadable {
110 |  |
111 |  |
         /**
112 |  |
          * Default Logger.
113 |  |
          */
114 | 1 |
         private static Logger logger = Logger.getLogger("grizzly");
115 |  |
116 |  |
         /**
117 |  |
          * The underlying SSLSelectorHandler used to mange SelectionKeys.
118 |  |
          */
119 |  |
         private SSLSelectorHandler selectorHandler;
120 |  |
121 |  |
         /**
122 |  |
          * A {@link SSLCallbackHandler} handler invoked by the SSLSelectorHandler
123 |  |
          * when a non blocking operation is ready to be processed.
124 |  |
          */
125 |  |
         private SSLCallbackHandler callbackHandler;
126 |  |
127 |  |
         /*
128 |  |
          * An empty ByteBuffer used for handshaking
129 |  |
          */
130 | 1 |
         private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0);
131 |  |
132 |  |
         /**
133 |  |
          * Input buffer for reading encrypted data from channel
134 |  |
          */
135 |  |
         private ByteBuffer securedInputBuffer;
136 |  |
137 |  |
         /**
138 |  |
          * Output buffer, which contains encrypted data ready for writing to channel
139 |  |
          */
140 |  |
         private ByteBuffer securedOutputBuffer;
141 |  |
142 |  |
         /**
143 |  |
          * Buffer, where application data could be written during a asynchronous handshaking.
144 |  |
          * It is set when user application calls: SSLConnectorHandler.handshake(appDataBuffer)
145 |  |
          * and references appDataBuffer.
146 |  |
          */
147 |  |
         private ByteBuffer asyncHandshakeBuffer;
148 |  |
149 |  |
         /**
150 |  |
          * The connection's SocketChannel.
151 |  |
          */
152 |  |
         private SocketChannel socketChannel;
153 |  |
154 |  |
         /**
155 |  |
          * Default {@link SSLContext}, created on
156 |  |
          * top of default <code>SSLConfiguration</code>
157 |  |
          */
158 |  |
         private static volatile SSLContext defaultSSLContext;
159 |  |
160 |  |
         /**
161 |  |
          * Is the connection established.
162 |  |
          */
163 |  |
         private volatile boolean isConnected;
164 |  |
165 |  |
         /**
166 |  |
          * Is the handshake phase completed
167 |  |
          */
168 |  |
         private volatile boolean isHandshakeDone;
169 |  |
170 |  |
         /**
171 |  |
          * The internal Controller used (in case not specified).
172 |  |
          */
173 |  |
         private Controller controller;
174 |  |
175 |  |
         /**
176 |  |
          * IsConnected Latch related
177 |  |
          */
178 |  |
         private CountDownLatch isConnectedLatch;
179 |  |
180 |  |
         /**
181 |  |
          * Are we creating a controller every run.
182 |  |
          */
183 | 14 |
         private boolean isStandalone = false;
184 |  |
185 |  |
         /**
186 |  |
          * Is async handshake in progress
187 |  |
          */
188 |  |
         private boolean isProcessingAsyncHandshake;
189 |  |
190 |  |
         /**
191 |  |
          * Result of last{@link SSLEngine} operation
192 |  |
          */
193 |  |
         private SSLEngineResult sslLastOperationResult;
194 |  |
195 |  |
         /**
196 |  |
          * Current handshake status
197 |  |
          */
198 |  |
         private SSLEngineResult.HandshakeStatus handshakeStatus;
199 |  |
200 |  |
         /**
201 |  |
          * Current{@link SSLEngine} status
202 |  |
          */
203 | 14 |
         private SSLEngineResult.Status sslEngineStatus = null;
204 |  |
205 |  |
206 |  |
         /**
207 |  |
          * Are we creating a controller every run.
208 |  |
          */
209 |  |
         private boolean delegateSSLTasks;
210 |  |
211 |  |
         /**
212 |  |
          * Connector's{@link SSLEngine}
213 |  |
          */
214 |  |
         private SSLEngine sslEngine;
215 |  |
216 |  |
         /**
217 |  |
          * Connector's {@link SSLContext}
218 |  |
          */
219 |  |
         private SSLContext sslContext;
220 |  |
221 |  |
         /**
222 |  |
          * SSL read postprocessor for <code>AsyncQueueReadable</code>
223 |  |
          */
224 |  |
         private volatile AsyncQueueDataProcessor sslReadPostProcessor;
225 |  |
226 |  |
         /**
227 |  |
          * SSL write preprocessor for <code>AsyncQueueWritable</code>
228 |  |
          */
229 |  |
         private volatile AsyncQueueDataProcessor sslWritePreProcessor;
230 |  |
231 |  |
         /**
232 |  |
          * Connector's write mode
233 |  |
          */
234 |  |
         private boolean isAsyncWriteQueueMode;
235 |  |
236 |  |
         /**
237 |  |
          * Connector's read mode
238 |  |
          */
239 |  |
         private boolean isAsyncReadQueueMode;
240 |  |
241 |  |
         public SSLConnectorHandler() {
242 | 14 |
             this(defaultSSLContext);
243 | 14 |
         }
244 |  |
245 |  |
         public SSLConnectorHandler(SSLConfig sslConfig) {
246 | 0 |
             this(sslConfig.createSSLContext());
247 | 0 |
         }
248 |  |
249 | 14 |
         public SSLConnectorHandler(SSLContext sslContext) {
250 | 14 |
             if (sslContext == null) {
251 | 1 |
                 if (defaultSSLContext == null) {
252 | 1 |
                     synchronized (SSLConnectorHandler.class) {
253 | 1 |
                         if (defaultSSLContext == null) {
254 | 1 |
                             defaultSSLContext = SSLConfig.DEFAULT_CONFIG.createSSLContext();
255 |  |
                         }
256 | 1 |
                     }
257 |  |
                 }
258 |  |
259 | 1 |
                 sslContext = defaultSSLContext;
260 |  |
             }
261 |  |
262 | 14 |
             this.sslContext = sslContext;
263 | 14 |
         }
264 |  |
265 |  |
         public boolean getDelegateSSLTasks() {
266 | 0 |
             return delegateSSLTasks;
267 |  |
         }
268 |  |
269 |  |
         public void setDelegateSSLTasks(boolean delegateSSLTasks) {
270 | 0 |
             this.delegateSSLTasks = delegateSSLTasks;
271 | 0 |
         }
272 |  |
273 |  |
         /**
274 |  |
          * Connect to hostname:port. When an aysnchronous event happens (e.g
275 |  |
          * OP_READ or OP_WRITE), the {@link Controller} will invoke
276 |  |
          * the {@link CallbackHandler}.
277 |  |
          * @param remoteAddress remote address to connect
278 |  |
          * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when
279 |  |
          *        a non blocking operation is ready to be handled. When null, all
280 |  |
          *        read and write operation will be delegated to the default
281 |  |
          *        {@link ProtocolChain} and its list of {@link ProtocolFilter}
282 |  |
          *        . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}.
283 |  |
          * @throws java.io.IOException
284 |  |
          */
285 |  |
         public void connect(SocketAddress remoteAddress, SSLCallbackHandler callbackHandler) throws IOException {
286 | 112 |
             connect(remoteAddress, null, callbackHandler);
287 | 112 |
         }
288 |  |
289 |  |
         /**
290 |  |
          * Connect to hostname:port. When an aysnchronous event happens (e.g
291 |  |
          * OP_READ or OP_WRITE), the {@link Controller} will invoke
292 |  |
          * the {@link CallbackHandler}.
293 |  |
          * @param remoteAddress remote address to connect
294 |  |
          * @param localAddress local address to bind
295 |  |
          * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when
296 |  |
          *        a non blocking operation is ready to be handled. When null, all
297 |  |
          *        read and write operation will be delegated to the default
298 |  |
          *        {@link ProtocolChain} and its list of {@link ProtocolFilter}
299 |  |
          *        . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}.
300 |  |
          * @throws java.io.IOException
301 |  |
          */
302 |  |
         public void connect(SocketAddress remoteAddress, SocketAddress localAddress, SSLCallbackHandler callbackHandler) throws IOException {
303 | 112 |
             if (controller == null) {
304 | 0 |
                 throw new IllegalStateException("Controller cannot be null");
305 |  |
             }
306 |  |
307 | 112 |
             connect(remoteAddress, localAddress, callbackHandler, (SSLSelectorHandler) controller.getSelectorHandler(protocol()));
308 | 112 |
         }
309 |  |
310 |  |
         /**
311 |  |
          * Connect to hostname:port. When an aysnchronous event happens (e.g
312 |  |
          * OP_READ or OP_WRITE), the {@link Controller} will invoke
313 |  |
          * the {@link CallbackHandler}.
314 |  |
          * @param remoteAddress remote address to connect
315 |  |
          * @param callbackHandler the handler invoked by the Controller when
316 |  |
          *        an non blocking operation is ready to be handled.
317 |  |
          * @param selectorHandler an instance of SelectorHandler.
318 |  |
          * @throws java.io.IOException
319 |  |
          */
320 |  |
         public void connect(SocketAddress remoteAddress, SSLCallbackHandler callbackHandler, SSLSelectorHandler selectorHandler) throws IOException {
321 | 0 |
             connect(remoteAddress, null, callbackHandler, selectorHandler);
322 | 0 |
         }
323 |  |
324 |  |
         /**
325 |  |
          * Connect to hostname:port. When an aysnchronous event happens (e.g
326 |  |
          * OP_READ or OP_WRITE), the {@link Controller} will invoke
327 |  |
          * the {@link CallbackHandler}.
328 |  |
          * @param remoteAddress remote address to connect
329 |  |
          * @param localAddress local address to bin
330 |  |
          * @param callbackHandler the handler invoked by its associated {@link SelectorHandler} when
331 |  |
          *        a non blocking operation is ready to be handled. When null, all
332 |  |
          *        read and write operation will be delegated to the default
333 |  |
          *        {@link ProtocolChain} and its list of {@link ProtocolFilter}
334 |  |
          *        . When null, this {@link ConnectorHandler} will create an instance of {@link DefaultCallbackHandler}.
335 |  |
          * @param selectorHandler an instance of SelectorHandler.
336 |  |
          * @throws java.io.IOException
337 |  |
          */
338 |  |
         public void connect(SocketAddress remoteAddress, SocketAddress localAddress,
339 |  |
                 SSLCallbackHandler callbackHandler,
340 |  |
                 SSLSelectorHandler selectorHandler) throws IOException {
341 | 122 |
             if (isConnected) {
342 | 0 |
                 throw new AlreadyConnectedException();
343 |  |
             }
344 |  |
345 | 122 |
             if (controller == null) {
346 | 0 |
                 throw new IllegalStateException("Controller cannot be null");
347 |  |
             }
348 |  |
349 | 122 |
             if (selectorHandler == null) {
350 | 0 |
                 throw new IllegalStateException("SelectorHandler cannot be null");
351 |  |
             }
352 |  |
353 | 122 |
             this.selectorHandler = selectorHandler;
354 | 122 |
             if (callbackHandler == null){
355 | 0 |
                 callbackHandler = new DefaultCallbackHandler(this);
356 |  |
             } else {
357 | 122 |
                 this.callbackHandler = callbackHandler;
358 |  |
             }
359 |  |
360 |  |
             // Wait for the onConnect to be invoked.
361 | 122 |
             isConnectedLatch = new CountDownLatch(1);
362 |  |
363 | 122 |
             selectorHandler.connect(remoteAddress, localAddress,
364 |  |
                     new SSLInternalCallbackHandler());
365 |  |
366 |  |
             try {
367 | 122 |
                 isConnectedLatch.await(30, TimeUnit.SECONDS);
368 | 0 |
             } catch (InterruptedException ex) {
369 | 0 |
                 throw new IOException(ex.getMessage());
370 | 122 |
             }
371 | 122 |
         }
372 |  |
373 |  |
         /**
374 |  |
          * Connect to hostname:port. Internally an instance of Controller and
375 |  |
          * its default SelectorHandler will be created everytime this method is
376 |  |
          * called. This method should be used only and only if no external
377 |  |
          * Controller has been initialized.
378 |  |
          * @param remoteAddress remote address to connect
379 |  |
          * @throws java.io.IOException
380 |  |
          */
381 |  |
         public void connect(SocketAddress remoteAddress) throws IOException {
382 | 10 |
             connect(remoteAddress, (SocketAddress) null);
383 | 10 |
         }
384 |  |
385 |  |
         /**
386 |  |
          * Connect to hostname:port. Internally an instance of Controller and
387 |  |
          * its default SelectorHandler will be created everytime this method is
388 |  |
          * called. This method should be used only and only if no external
389 |  |
          * Controller has been initialized.
390 |  |
          * @param remoteAddress remote address to connect
391 |  |
          * @throws java.io.IOException
392 |  |
          * @param localAddress local address to bin
393 |  |
          */
394 |  |
         public void connect(SocketAddress remoteAddress, SocketAddress localAddress) throws IOException {
395 | 10 |
             if (isConnected) {
396 | 0 |
                 throw new AlreadyConnectedException();
397 |  |
             }
398 |  |
399 | 10 |
             if (controller == null) {
400 | 10 |
                 isStandalone = true;
401 | 10 |
                 controller = new Controller();
402 | 10 |
                 controller.setSelectorHandler(new SSLSelectorHandler(true));
403 | 10 |
                 DefaultPipeline pipeline = new DefaultPipeline();
404 | 10 |
                 pipeline.initPipeline();
405 | 10 |
                 pipeline.startPipeline();
406 | 10 |
                 controller.setPipeline(pipeline);
407 |  |
408 | 10 |
                 final CountDownLatch latch = new CountDownLatch(1);
409 | 10 |
                 controller.addStateListener(new ControllerStateListenerAdapter() {
410 |  |
                     @Override
411 |  |
                     public void onReady() {
412 | 10 |
                         latch.countDown();
413 | 10 |
                     }
414 |  |
415 |  |
                     @Override
416 |  |
                     public void onException(Throwable e) {
417 | 0 |
                         if (latch.getCount() > 0) {
418 | 0 |
                             logger.log(Level.SEVERE, "Error occured on Controller startup: ", e);
419 |  |
                         }
420 |  |
421 | 0 |
                         latch.countDown();
422 | 0 |
                     }
423 |  |
                 });
424 | 10 |
                 callbackHandler = new DefaultCallbackHandler(this,false);
425 | 10 |
                 new Thread(controller, "GrizzlySSLConnectorHandler-Controller").start();
426 |  |
427 |  |
                 try {
428 | 10 |
                     latch.await();
429 | 0 |
                 } catch (InterruptedException ex) {
430 | 10 |
                 }
431 |  |
             }
432 |  |
433 | 10 |
             connect(remoteAddress, localAddress, callbackHandler, (SSLSelectorHandler)
434 |  |
                     controller.getSelectorHandler(protocol()));
435 | 10 |
         }
436 |  |
437 |  |
         /**
438 |  |
          * Initiate SSL handshake phase.
439 |  |
          * Handshake is required to be done after connection established.
440 |  |
          *
441 |  |
          * @param byteBuffer Application {@link ByteBuffer}, where application data
442 |  |
          * will be stored
443 |  |
          * @param blocking true, if handshake should be done in blocking mode, for non-blocking false
444 |  |
          * @return If blocking parameter is true - method should always return true if handshake is done,
445 |  |
          * or throw IOException otherwise. For non-blocking mode method returns true if handshake is done, or false
446 |  |
          * if handshake will be completed in non-blocking manner.
447 |  |
          * If False returned - <code>SSLConnectorHandler</code> will call callbackHandler.onHandshake() to notify
448 |  |
          * about finishing handshake phase.
449 |  |
          * @throws java.io.IOException if some error occurs during processing I/O operations/
450 |  |
          */
451 |  |
         public boolean handshake(ByteBuffer byteBuffer, boolean blocking) throws IOException {
452 | 122 |
             sslEngine.beginHandshake();
453 | 122 |
             handshakeStatus = sslEngine.getHandshakeStatus();
454 |  |
455 | 122 |
             if (blocking) {
456 | 120 |
                 SSLUtils.doHandshake(socketChannel, byteBuffer, securedInputBuffer,
457 |  |
                         securedOutputBuffer, sslEngine, handshakeStatus);
458 | 120 |
                 securedOutputBuffer.limit(securedOutputBuffer.position());
459 | 120 |
                 finishHandshake();
460 |  |
461 |  |
                 // Sync should be always done
462 | 120 |
                 return true;
463 |  |
             } else {
464 | 2 |
                 return doAsyncHandshake(byteBuffer);
465 |  |
             }
466 |  |
         }
467 |  |
468 |  |
         /**
469 |  |
          * Read bytes. If blocking is set to <tt>true</tt>, a pool of temporary
470 |  |
          * {@link Selector} will be used to read bytes.
471 |  |
          * @param byteBuffer The byteBuffer to store bytes.
472 |  |
          * @param blocking <tt>true</tt> if a a pool of temporary Selector
473 |  |
          *        is required to handle a blocking read.
474 |  |
          * @return number of bytes read from a channel.
475 |  |
          * Be careful, because return value represents the length of encrypted data,
476 |  |
          * which was read from a channel. Don't use return value to determine the
477 |  |
          * availability of a decrypted data to process, but use byteBuffer.remaining().
478 |  |
          * @throws java.io.IOException
479 |  |
          */
480 |  |
         public long read(ByteBuffer byteBuffer, boolean blocking) throws IOException {
481 | 83023 |
             if (!isConnected) {
482 | 0 |
                 throw new NotYetConnectedException();
483 |  |
             }
484 |  |
485 | 83023 |
             if (blocking) {
486 | 100 |
                 return SSLUtils.doSecureRead(socketChannel, sslEngine,
487 |  |
                         byteBuffer, securedInputBuffer);
488 |  |
             } else {
489 | 82923 |
                 isAsyncReadQueueMode = false;
490 | 82923 |
                 int nRead = doReadAsync(byteBuffer);
491 |  |
492 | 82923 |
                 if (nRead == 0) {
493 | 40610 |
                     registerSelectionKeyFor(SelectionKey.OP_READ);
494 |  |
                 }
495 |  |
496 | 82923 |
                 return nRead;
497 |  |
             }
498 |  |
         }
499 |  |
500 |  |
501 |  |
         /**
502 |  |
          * Writes bytes. If blocking is set to <tt>true</tt>, a pool of temporary
503 |  |
          * {@link Selector} will be used to writes bytes.
504 |  |
          * @param byteBuffer The byteBuffer to write.
505 |  |
          * @param blocking <tt>true</tt> if a a pool of temporary Selector
506 |  |
          *        is required to handle a blocking write.
507 |  |
          * @return number of bytes written on a channel.
508 |  |
          * Be careful, as non-crypted data is passed, but crypted data is written
509 |  |
          * on channel. Don't use return value to determine the
510 |  |
          * number of bytes from original buffer, which were written.
511 |  |
          * @throws java.io.IOException
512 |  |
          */
513 |  |
         public long write(ByteBuffer byteBuffer, boolean blocking) throws IOException {
514 | 102 |
             if (!isConnected) {
515 | 0 |
                 throw new NotYetConnectedException();
516 |  |
             }
517 |  |
518 | 102 |
             if (blocking) {
519 | 100 |
                 long nWrite = SSLOutputWriter.flushChannel(socketChannel,
520 |  |
                         byteBuffer, securedOutputBuffer, sslEngine);
521 |  |
                 // Mark securedOutputBuffer as empty
522 | 100 |
                 securedOutputBuffer.position(securedOutputBuffer.limit());
523 | 100 |
                 return nWrite;
524 |  |
             } else {
525 | 2 |
                 if (callbackHandler == null) {
526 | 0 |
                     throw new IllegalStateException("Non blocking write needs a CallbackHandler");
527 |  |
                 }
528 |  |
529 | 2 |
                 isAsyncWriteQueueMode = false;
530 | 2 |
                 int nWrite = 1;
531 | 2 |
                 int totalWrite = 0;
532 |  |
533 | 4 |
                 while (nWrite > 0 &&
534 |  |
                         (byteBuffer.hasRemaining() || securedOutputBuffer.hasRemaining())) {
535 | 2 |
                     nWrite = doWriteAsync(byteBuffer);
536 | 2 |
                     totalWrite += nWrite;
537 |  |
                 }
538 |  |
539 | 2 |
                 if (byteBuffer.hasRemaining() || securedOutputBuffer.hasRemaining()) {
540 | 0 |
                     registerSelectionKeyFor(SelectionKey.OP_WRITE);
541 |  |
                 }
542 |  |
543 | 2 |
                 return totalWrite;
544 |  |
             }
545 |  |
         }
546 |  |
547 |  |
548 |  |
         /**
549 |  |
          * {@inheritDoc}
550 |  |
          */
551 |  |
         public void writeToAsyncQueue(ByteBuffer buffer) throws IOException {
552 | 599434 |
             writeToAsyncQueue(buffer, null);
553 | 600000 |
         }
554 |  |
555 |  |
556 |  |
         /**
557 |  |
          * {@inheritDoc}
558 |  |
          */
559 |  |
         public void writeToAsyncQueue(ByteBuffer buffer,
560 |  |
                 AsyncWriteCallbackHandler callbackHandler) throws IOException {
561 | 599443 |
             writeToAsyncQueue(buffer, callbackHandler, obtainSSLWritePreProcessor());
562 | 599998 |
         }
563 |  |
564 |  |
565 |  |
         /**
566 |  |
          * {@inheritDoc}
567 |  |
          */
568 |  |
         public void writeToAsyncQueue(ByteBuffer buffer,
569 |  |
                 AsyncWriteCallbackHandler callbackHandler,
570 |  |
                 AsyncQueueDataProcessor writePreProcessor) throws IOException {
571 | 600000 |
             writeToAsyncQueue(buffer, callbackHandler, writePreProcessor, false);
572 | 600000 |
         }
573 |  |
574 |  |
575 |  |
         /**
576 |  |
          * {@inheritDoc}
577 |  |
          */
578 |  |
         public void writeToAsyncQueue(ByteBuffer buffer,
579 |  |
                 AsyncWriteCallbackHandler callbackHandler,
580 |  |
                 AsyncQueueDataProcessor writePreProcessor,
581 |  |
                 boolean isCloneByteBuffer) throws IOException {
582 | 600000 |
             isAsyncWriteQueueMode = true;
583 | 600000 |
             selectorHandler.getAsyncQueueWriter().write(
584 |  |
                     socketChannel.keyFor(selectorHandler.getSelector()), buffer,
585 |  |
                     callbackHandler, writePreProcessor, isCloneByteBuffer);
586 | 600000 |
         }
587 |  |
588 |  |
589 |  |
         /**
590 |  |
          * {@inheritDoc}
591 |  |
          */
592 |  |
         public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer)
593 |  |
                 throws IOException {
594 | 0 |
             writeToAsyncQueue(dstAddress, buffer);
595 | 0 |
         }
596 |  |
597 |  |
598 |  |
         /**
599 |  |
          * {@inheritDoc}
600 |  |
          */
601 |  |
         public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer,
602 |  |
                 AsyncWriteCallbackHandler callbackHandler) throws IOException {
603 | 0 |
             writeToAsyncQueue(dstAddress, buffer, callbackHandler, obtainSSLWritePreProcessor());
604 | 0 |
         }
605 |  |
606 |  |
607 |  |
         /**
608 |  |
          * {@inheritDoc}
609 |  |
          */
610 |  |
         public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer,
611 |  |
                 AsyncWriteCallbackHandler callbackHandler,
612 |  |
                 AsyncQueueDataProcessor writePreProcessor) throws IOException {
613 | 0 |
             writeToAsyncQueue(dstAddress, buffer, callbackHandler, writePreProcessor);
614 | 0 |
         }
615 |  |
616 |  |
617 |  |
         /**
618 |  |
          * {@inheritDoc}
619 |  |
          */
620 |  |
         public void writeToAsyncQueue(SocketAddress dstAddress, ByteBuffer buffer,
621 |  |
                 AsyncWriteCallbackHandler callbackHandler,
622 |  |
                 AsyncQueueDataProcessor writePreProcessor, boolean isCloneByteBuffer)
623 |  |
                 throws IOException {
624 | 0 |
             isAsyncWriteQueueMode = true;
625 | 0 |
             selectorHandler.getAsyncQueueWriter().write(
626 |  |
                     socketChannel.keyFor(selectorHandler.getSelector()), dstAddress,
627 |  |
                     buffer, callbackHandler, writePreProcessor, isCloneByteBuffer);
628 | 0 |
         }
629 |  |
630 |  |
631 |  |
         /**
632 |  |
          * {@inheritDoc}
633 |  |
          */
634 |  |
         public void readFromAsyncQueue(ByteBuffer buffer,
635 |  |
                 AsyncReadCallbackHandler callbackHandler) throws IOException {
636 | 0 |
             readFromAsyncQueue(buffer, callbackHandler, null);
637 | 0 |
         }
638 |  |
639 |  |
640 |  |
         /**
641 |  |
          * {@inheritDoc}
642 |  |
          */
643 |  |
         public void readFromAsyncQueue(ByteBuffer buffer,
644 |  |
                 AsyncReadCallbackHandler callbackHandler,
645 |  |
                 AsyncReadCondition condition) throws IOException {
646 | 100 |
             readFromAsyncQueue(buffer, callbackHandler, condition,
647 |  |
                     obtainSSLReadPostProcessor());
648 | 100 |
         }
649 |  |
650 |  |
651 |  |
         /**
652 |  |
          * {@inheritDoc}
653 |  |
          */
654 |  |
         public void readFromAsyncQueue(ByteBuffer buffer,
655 |  |
                 AsyncReadCallbackHandler callbackHandler,
656 |  |
                 AsyncReadCondition condition,
657 |  |
                 AsyncQueueDataProcessor readPostProcessor) throws IOException {
658 | 100 |
             isAsyncReadQueueMode = true;
659 | 100 |
             selectorHandler.getAsyncQueueReader().read(
660 |  |
                     socketChannel.keyFor(selectorHandler.getSelector()), buffer,
661 |  |
                     callbackHandler, condition, readPostProcessor);
662 | 100 |
         }
663 |  |
664 |  |
665 |  |
         /**
666 |  |
          * Close the underlying connection.
667 |  |
          */
668 |  |
         public void close() throws IOException {
669 | 122 |
             if (socketChannel != null) {
670 | 122 |
                 if (isConnected) {
671 |  |
                     try {
672 | 122 |
                         if (securedOutputBuffer.hasRemaining()) {
673 |  |
                             // if there is something is securedOutputBuffer - flush it
674 | 0 |
                             OutputWriter.flushChannel(socketChannel, securedOutputBuffer);
675 |  |
                         }
676 |  |
677 |  |
                         // Close secure outbound channel and flush data
678 | 122 |
                         sslEngine.closeOutbound();
679 | 122 |
                         SSLUtils.wrap(EMPTY_BUFFER, securedOutputBuffer, sslEngine);
680 | 122 |
                         OutputWriter.flushChannel(socketChannel, securedOutputBuffer);
681 | 0 |
                     } catch (IOException e) {
682 | 0 |
                         logger.log(Level.FINE, "IOException during closing the connector.", e);
683 | 122 |
                     }
684 |  |
                 }
685 |  |
686 | 122 |
                 if (selectorHandler != null) {
687 | 122 |
                     SelectionKey key = socketChannel.keyFor(selectorHandler.getSelector());
688 |  |
689 | 122 |
                     if (key == null) {
690 | 0 |
                         return;
691 |  |
                     }
692 | 122 |
                     selectorHandler.getSelectionKeyHandler().close(key);
693 |  |
                 }
694 |  |
695 | 122 |
                 socketChannel.close();
696 |  |
             }
697 |  |
698 | 122 |
             if (controller != null && isStandalone) {
699 | 10 |
                 controller.stop();
700 | 10 |
                 controller = null;
701 |  |
             }
702 |  |
703 | 122 |
             sslEngine = null;
704 | 122 |
             asyncHandshakeBuffer = null;
705 | 122 |
             isStandalone = false;
706 | 122 |
             isConnected = false;
707 | 122 |
             isHandshakeDone = false;
708 | 122 |
         }
709 |  |
710 |  |
711 |  |
         /**
712 |  |
          * Finish handling the OP_CONNECT interest ops.
713 |  |
          * @param key - a {@link SelectionKey}
714 |  |
          */
715 |  |
         public void finishConnect(SelectionKey key) throws IOException{
716 |  |
             try {
717 | 122 |
                 if (logger.isLoggable(Level.FINE)) {
718 | 0 |
                     logger.log(Level.FINE, "Finish connect");
719 |  |
                 }
720 |  |
721 | 122 |
                 socketChannel = (SocketChannel) key.channel();
722 | 122 |
                 socketChannel.finishConnect();
723 | 122 |
                 isConnected = socketChannel.isConnected();
724 | 122 |
                 if (isConnected) {
725 | 122 |
                     initSSLEngineIfRequired();
726 |  |
                 }
727 | 0 |
             } catch (IOException e) {
728 | 0 |
                 throw e;
729 |  |
             } finally {
730 | 122 |
                 isConnectedLatch.countDown();
731 | 122 |
             }
732 | 122 |
         }
733 |  |
734 |  |
         /**
735 |  |
          * Changes SSLConnectorHandler state, after handshake operation is done.
736 |  |
          * Normally should not be called by outside Grizzly, just in case when custom
737 |  |
          * handshake code was used.
738 |  |
          */
739 |  |
         public void finishHandshake() {
740 | 122 |
             isProcessingAsyncHandshake = false;
741 | 122 |
             isHandshakeDone = true;
742 | 122 |
         }
743 |  |
744 |  |
         /**
745 |  |
          * A token decribing the protocol supported by an implementation of this
746 |  |
          * interface
747 |  |
          * @return this {@link ConnectorHandler}'s protocol
748 |  |
          */
749 |  |
         public Controller.Protocol protocol() {
750 | 234 |
             return Controller.Protocol.TLS;
751 |  |
         }
752 |  |
753 |  |
754 |  |
         /**
755 |  |
          * Is the underlying SocketChannel connected.
756 |  |
          * @return <tt>true</tt> if connected, otherwise <tt>false</tt>
757 |  |
          */
758 |  |
         public boolean isConnected() {
759 | 132 |
             return isConnected && socketChannel.isOpen();
760 |  |
         }
761 |  |
762 |  |
         /**
763 |  |
          * Is the underlying SocketChannel connected.
764 |  |
          * @return <tt>true</tt> if connected, otherwise <tt>false</tt>
765 |  |
          */
766 |  |
         public boolean isHandshakeDone() {
767 | 112 |
             return isHandshakeDone && !isProcessingAsyncHandshake;
768 |  |
         }
769 |  |
770 |  |
771 |  |
         /**
772 |  |
          * Get SSLConnector's {@link SSLContext}
773 |  |
          */
774 |  |
         public SSLContext getSSLContext() {
775 | 0 |
             return sslContext;
776 |  |
         }
777 |  |
778 |  |
779 |  |
         /**
780 |  |
          * Set {@link SSLContext}.
781 |  |
          * Use this method to change SSLConnectorHandler configuration.
782 |  |
          * New configuration will become active only after SSLConnector
783 |  |
          * will be closed and connected again.
784 |  |
          */
785 |  |
         public void setSSLContext(SSLContext sslContext) {
786 | 0 |
             this.sslContext = sslContext;
787 | 0 |
         }
788 |  |
789 |  |
790 |  |
         /**
791 |  |
          * Configure SSLConnectorHandler's SSL settings.
792 |  |
          *
793 |  |
          * Use this method to change SSLConnectorHandler configuration.
794 |  |
          * New configuration will become active only after SSLConnector
795 |  |
          * will be closed and connected again.
796 |  |
          */
797 |  |
         public void configure(SSLConfig sslConfig) {
798 | 0 |
             this.sslContext = sslConfig.createSSLContext();
799 | 0 |
         }
800 |  |
801 |  |
         /**
802 |  |
          * Returns SSLConnector's{@link SSLEngine}
803 |  |
          * @return{@link SSLEngine}
804 |  |
          */
805 |  |
         public SSLEngine getSSLEngine() {
806 | 0 |
             return sslEngine;
807 |  |
         }
808 |  |
809 |  |
         /**
810 |  |
          * Set{@link SSLEngine}
811 |  |
          * @param sslEngine{@link SSLEngine}
812 |  |
          */
813 |  |
         public void setSSLEngine(SSLEngine sslEngine) {
814 | 0 |
             this.sslEngine = sslEngine;
815 | 0 |
         }
816 |  |
817 |  |
         /**
818 |  |
          * Returns <code>SSLConnectorHandler</code>'s secured input buffer, it
819 |  |
          * uses for reading data from a socket channel.
820 |  |
          * @return secured input {@link ByteBuffer}
821 |  |
          */
822 |  |
         public ByteBuffer getSecuredInputBuffer() {
823 | 0 |
             return securedInputBuffer;
824 |  |
         }
825 |  |
826 |  |
         /**
827 |  |
          * Returns <code>SSLConnectorHandler</code>'s secured output buffer, it
828 |  |
          * uses for writing data to a socket channel.
829 |  |
          * @return secured output {@link ByteBuffer}
830 |  |
          */
831 |  |
         public ByteBuffer getSecuredOutputBuffer() {
832 | 0 |
             return securedOutputBuffer;
833 |  |
         }
834 |  |
835 |  |
         /**
836 |  |
          * Return the  {@link Controller}
837 |  |
          * @return the  {@link Controller}
838 |  |
          */
839 |  |
         public Controller getController() {
840 | 0 |
             return controller;
841 |  |
         }
842 |  |
843 |  |
844 |  |
         /**
845 |  |
          * Set the {@link Controller} to use with this instance.
846 |  |
          * @param controller the {@link Controller} to use with this instance.
847 |  |
          */
848 |  |
         public void setController(Controller controller) {
849 | 335 |
             this.controller = controller;
850 | 335 |
         }
851 |  |
852 |  |
853 |  |
         /**
854 |  |
          * Return the current {@link SocketChannel} used.
855 |  |
          * @return the current {@link SocketChannel} used.
856 |  |
          */
857 |  |
         public SelectableChannel getUnderlyingChannel() {
858 | 0 |
             return socketChannel;
859 |  |
         }
860 |  |
861 |  |
862 |  |
         /**
863 |  |
          * Set the {@link SocketChannel}.
864 |  |
          * @param the {@link SocketChannel} to use.
865 |  |
          */
866 |  |
         protected void setUnderlyingChannel(SocketChannel socketChannel){
867 | 10 |
             this.socketChannel = socketChannel;
868 | 10 |
         }
869 |  |
870 |  |
871 |  |
         /**
872 |  |
          * Return the {@link CallbackHandler}.
873 |  |
          * @return the {@link CallbackHandler}.
874 |  |
          */
875 |  |
         public SSLCallbackHandler getCallbackHandler() {
876 | 0 |
             return callbackHandler;
877 |  |
         }
878 |  |
879 |  |
880 |  |
         /**
881 |  |
          * Set the {@link CallbackHandler}.
882 |  |
          * @param callbackHandler the {@link CallbackHandler}.
883 |  |
          */
884 |  |
         public void setCallbackHandler(SSLCallbackHandler callbackHandler) {
885 | 0 |
             this.callbackHandler = callbackHandler;
886 | 0 |
         }
887 |  |
888 |  |
889 |  |
         /**
890 |  |
          * Return the associated {@link SelectorHandler}.
891 |  |
          * @return the associated {@link SelectorHandler}.
892 |  |
          */
893 |  |
         public SSLSelectorHandler getSelectorHandler() {
894 | 0 |
             return selectorHandler;
895 |  |
         }
896 |  |
897 |  |
         /**
898 |  |
          * Gets the size of the largest application buffer that may occur when
899 |  |
          * using this session.
900 |  |
          * SSLEngine application data buffers must be large enough to hold the
901 |  |
          * application data from any inbound network application data packet
902 |  |
          * received. Typically, outbound application data buffers can be of any size.
903 |  |
          *
904 |  |
          * (javadoc is taken from SSLSession.getApplicationBufferSize())
905 |  |
          * @return largets application buffer size, which may occur
906 |  |
          */
907 |  |
         public int getApplicationBufferSize() {
908 | 222 |
             initSSLEngineIfRequired();
909 | 222 |
             return sslEngine.getSession().getApplicationBufferSize();
910 |  |
         }
911 |  |
912 |  |
         /**
913 |  |
          * Read a data from channel in async mode and decrypt
914 |  |
          * @param byteBuffer buffer for decrypted data
915 |  |
          * @return number of bytes read from a channel
916 |  |
          * @throws java.io.IOException
917 |  |
          */
918 |  |
         private int doReadAsync(ByteBuffer byteBuffer) throws IOException {
919 |  |
             // Clear or compact secured input buffer
920 | 82931 |
             clearOrCompactBuffer(securedInputBuffer);
921 |  |
922 |  |
             // Read data to secured buffer
923 | 82931 |
             int bytesRead = socketChannel.read(securedInputBuffer);
924 |  |
925 | 82931 |
             if (bytesRead == -1) {
926 |  |
                 try {
927 | 1 |
                     sslEngine.closeInbound();
928 |  |
                     // check if there is some secured data still available
929 | 0 |
                     if (securedInputBuffer.position() == 0 ||
930 |  |
                             sslEngineStatus == SSLEngineResult.Status.BUFFER_UNDERFLOW) {
931 | 0 |
                         return -1;
932 |  |
                     }
933 | 1 |
                 } catch (SSLException e) {
934 | 1 |
                     return -1;
935 | 0 |
                 }
936 |  |
             }
937 |  |
938 | 82930 |
             securedInputBuffer.flip();
939 |  |
940 | 82930 |
             if (bytesRead == 0 && !securedInputBuffer.hasRemaining()) {
941 | 40605 |
                 return 0;
942 |  |
             }
943 |  |
944 | 42325 |
             int bytesProduced = unwrapAll(byteBuffer);
945 |  |
946 | 42325 |
             if (bytesProduced == 0) {
947 | 34 |
                 if (sslEngineStatus == SSLEngineResult.Status.CLOSED) {
948 | 0 |
                     return -1;
949 | 34 |
                 } else if (sslEngineStatus == SSLEngineResult.Status.BUFFER_OVERFLOW) {
950 | 0 |
                     throw new BufferOverflowException();
951 |  |
                 }
952 |  |
             }
953 |  |
954 | 42325 |
             return bytesRead;
955 |  |
         }
956 |  |
957 |  |
         private int unwrapAll(ByteBuffer byteBuffer) throws SSLException {
958 | 50894 |
             SSLEngineResult result = null;
959 | 50894 |
             int bytesProduced = 0;
960 |  |
961 |  |
             do {
962 | 103638 |
                 result = sslEngine.unwrap(securedInputBuffer, byteBuffer);
963 | 103638 |
                 bytesProduced += result.bytesProduced();
964 |  |
                 // During handshake phase several unwrap actions could be executed on read data
965 | 103638 |
             } while (result.getStatus() == SSLEngineResult.Status.OK &&
966 |  |
                     (isHandshakeDone || (result.getHandshakeStatus() ==
967 |  |
                     SSLEngineResult.HandshakeStatus.NEED_UNWRAP &&
968 |  |
                     result.bytesProduced() == 0)));
969 |  |
970 | 50894 |
             updateSSLEngineStatus(result);
971 | 50894 |
             return bytesProduced;
972 |  |
         }
973 |  |
974 |  |
         /**
975 |  |
          * Write secured data to channel in async mode
976 |  |
          *
977 |  |
          * @param byteBuffer non-crypted data buffer
978 |  |
          * @return number of bytes written on a channel.
979 |  |
          * Be careful, as non-crypted data is passed, but crypted data is written
980 |  |
          * on channel. Don't use return value to determine,
981 |  |
          * number of bytes from original buffer, which were written.
982 |  |
          * @throws java.io.IOException
983 |  |
          */
984 |  |
         private int doWriteAsync(ByteBuffer byteBuffer) throws IOException {
985 | 2 |
             if (securedOutputBuffer.hasRemaining() && !flushSecuredOutputBuffer()) {
986 | 0 |
                 return 0;
987 |  |
             }
988 |  |
989 | 2 |
             securedOutputBuffer.clear();
990 | 2 |
             SSLEngineResult result = SSLUtils.wrap(byteBuffer, securedOutputBuffer, sslEngine);
991 |  |
992 | 2 |
             updateSSLEngineStatus(result);
993 |  |
994 | 2 |
             return socketChannel.write(securedOutputBuffer);
995 |  |
996 |  |
         }
997 |  |
998 |  |
         /**
999 |  |
          * Perform an SSL handshake in async mode.
1000 |  |
          * @param byteBuffer The application {@link ByteBuffer}
1001 |  |
          *
1002 |  |
          * @throws IOException if the handshake fail.
1003 |  |
          */
1004 |  |
         private boolean doAsyncHandshake(ByteBuffer byteBuffer) throws IOException {
1005 |  |
             SSLEngineResult result;
1006 | 6 |
             isProcessingAsyncHandshake = true;
1007 | 6 |
             asyncHandshakeBuffer = byteBuffer;
1008 | 14 |
             while (handshakeStatus != HandshakeStatus.FINISHED) {
1009 | 1 |
                 switch (handshakeStatus) {
1010 |  |
                     case NEED_WRAP:
1011 | 8 |
                         result = SSLUtils.wrap(EMPTY_BUFFER, securedOutputBuffer, sslEngine);
1012 | 8 |
                         updateSSLEngineStatus(result);
1013 | 1 |
                         switch (result.getStatus()) {
1014 |  |
                             case OK:
1015 | 8 |
                                 if (!flushSecuredOutputBuffer()) {
1016 | 0 |
                                     return false;
1017 |  |
                                 }
1018 |  |
                                 break;
1019 |  |
                             default:
1020 | 0 |
                                 throw new IOException("Handshaking error: " + result.getStatus());
1021 |  |
                         }
1022 |  |
1023 | 8 |
                         if (handshakeStatus != HandshakeStatus.NEED_UNWRAP) {
1024 | 4 |
                             break;
1025 |  |
                         }
1026 |  |
                     case NEED_UNWRAP:
1027 | 8 |
                         int bytesRead = doReadAsync(byteBuffer);
1028 | 8 |
                         if (bytesRead == -1) {
1029 |  |
                             try {
1030 | 0 |
                                 sslEngine.closeInbound();
1031 | 0 |
                             } catch (IOException e) {
1032 | 0 |
                                 logger.log(Level.FINE, "Exception occured when closing sslEngine inbound.", e);
1033 | 0 |
                             }
1034 |  |
1035 | 0 |
                             throw new EOFException("Connection closed");
1036 | 8 |
                         } else if (bytesRead == 0 && sslLastOperationResult.bytesConsumed() == 0) {
1037 | 4 |
                             registerSelectionKeyFor(SelectionKey.OP_READ);
1038 | 4 |
                             return false;
1039 |  |
                         }
1040 |  |
1041 | 4 |
                         if (handshakeStatus != HandshakeStatus.NEED_TASK) {
1042 | 2 |
                             break;
1043 |  |
                         }
1044 |  |
                     case NEED_TASK:
1045 | 2 |
                         handshakeStatus = executeDelegatedTask();
1046 | 2 |
                         break;
1047 |  |
                     default:
1048 | 0 |
                         throw new RuntimeException("Invalid Handshaking State" + handshakeStatus);
1049 |  |
                 }
1050 |  |
             }
1051 |  |
1052 | 2 |
             if (isProcessingAsyncHandshake) {
1053 | 2 |
                 finishHandshake();
1054 |  |
             }
1055 |  |
1056 | 2 |
             asyncHandshakeBuffer = null;
1057 | 2 |
             return true;
1058 |  |
         }
1059 |  |
1060 |  |
         /**
1061 |  |
          * Complete hanshakes operations.
1062 |  |
          * @return SSLEngineResult.HandshakeStatus
1063 |  |
          */
1064 |  |
         private SSLEngineResult.HandshakeStatus executeDelegatedTask() {
1065 |  |
             Runnable runnable;
1066 | 4 |
             while ((runnable = sslEngine.getDelegatedTask()) != null) {
1067 | 2 |
                 runnable.run();
1068 |  |
             }
1069 |  |
1070 | 2 |
             return sslEngine.getHandshakeStatus();
1071 |  |
         }
1072 |  |
1073 |  |
         /**
1074 |  |
          * Update <code>SSLConnectorHandler</code> internal status with
1075 |  |
          * last{@link SSLEngine} operation result.
1076 |  |
          *
1077 |  |
          * @param result last{@link SSLEngine} operation result
1078 |  |
          */
1079 |  |
         private void updateSSLEngineStatus(SSLEngineResult result) {
1080 | 650893 |
             sslLastOperationResult = result;
1081 | 650903 |
             sslEngineStatus = result.getStatus();
1082 | 650902 |
             handshakeStatus = result.getHandshakeStatus();
1083 | 650901 |
         }
1084 |  |
1085 |  |
         /**
1086 |  |
          * Clears buffer if there is no info available, or compact buffer otherwise.
1087 |  |
          * @param buffer byte byffer
1088 |  |
          */
1089 |  |
         private static void clearOrCompactBuffer(ByteBuffer buffer) {
1090 | 91500 |
             if (!buffer.hasRemaining()) {
1091 | 91368 |
                 buffer.clear();
1092 | 132 |
             } else if (buffer.remaining() < buffer.capacity()) {
1093 | 30 |
                 buffer.compact();
1094 |  |
             }
1095 | 91500 |
         }
1096 |  |
1097 |  |
         /**
1098 |  |
          * Gets <code>SSLConnectorHandler</code> {@link SelectionKey}
1099 |  |
          * @return {@link SelectionKey}
1100 |  |
          */
1101 |  |
         private SelectionKey getSelectionKey() {
1102 | 40614 |
             return socketChannel.keyFor(selectorHandler.getSelector());
1103 |  |
         }
1104 |  |
1105 |  |
         /**
1106 |  |
          * Registers <code>SSLConnectorHandler<code>'s {@link SelectionKey}
1107 |  |
          * to listen channel operations.
1108 |  |
          * @param ops interested channel operations
1109 |  |
          */
1110 |  |
         private void registerSelectionKeyFor(int ops) {
1111 | 40614 |
             SelectionKey key = getSelectionKey();
1112 | 40614 |
             selectorHandler.register(key, ops);
1113 | 40614 |
         }
1114 |  |
1115 |  |
         /**
1116 |  |
          * Flushes as much as possible bytes from the secured output buffer
1117 |  |
          * @return true if secured buffer was completely flushed, false otherwise
1118 |  |
          */
1119 |  |
         private boolean flushSecuredOutputBuffer() throws IOException {
1120 | 8 |
             int nWrite = 1;
1121 |  |
1122 | 16 |
             while (nWrite > 0 && securedOutputBuffer.hasRemaining()) {
1123 | 8 |
                 nWrite = socketChannel.write(securedOutputBuffer);
1124 |  |
             }
1125 |  |
1126 | 8 |
             if (securedOutputBuffer.hasRemaining()) {
1127 | 0 |
                 SelectionKey key = socketChannel.keyFor(selectorHandler.getSelector());
1128 | 0 |
                 selectorHandler.register(key, SelectionKey.OP_WRITE);
1129 |  |
1130 | 0 |
                 return false;
1131 |  |
             }
1132 |  |
1133 | 8 |
             return true;
1134 |  |
         }
1135 |  |
1136 |  |
         /**
1137 |  |
          * Initiate{@link SSLEngine} and related secure buffers
1138 |  |
          */
1139 |  |
         private void initSSLEngineIfRequired() {
1140 | 344 |
             if (sslEngine == null) {
1141 | 122 |
                 sslEngine = sslContext.createSSLEngine();
1142 | 122 |
                 sslEngine.setUseClientMode(true);
1143 |  |
             }
1144 |  |
1145 | 344 |
             int bbSize = sslEngine.getSession().getPacketBufferSize();
1146 | 344 |
             securedInputBuffer = ByteBuffer.allocate(bbSize * 2);
1147 | 344 |
             securedOutputBuffer = ByteBuffer.allocate(bbSize * 2);
1148 | 344 |
             securedOutputBuffer.limit(0);
1149 | 344 |
         }
1150 |  |
1151 |  |
         private AsyncQueueDataProcessor obtainSSLReadPostProcessor() {
1152 | 100 |
             if (sslReadPostProcessor == null) {
1153 | 1 |
                 synchronized(this) {
1154 | 1 |
                     if (sslReadPostProcessor == null) {
1155 | 1 |
                         sslReadPostProcessor = new SSLReadPostProcessor();
1156 |  |
                     }
1157 | 1 |
                 }
1158 |  |
             }
1159 |  |
1160 | 100 |
             return sslReadPostProcessor;
1161 |  |
         }
1162 |  |
1163 |  |
         private AsyncQueueDataProcessor obtainSSLWritePreProcessor() {
1164 | 600000 |
             if (sslWritePreProcessor == null) {
1165 | 4 |
                 synchronized(this) {
1166 | 4 |
                     if (sslWritePreProcessor == null) {
1167 | 2 |
                         sslWritePreProcessor = new SSLWritePreProcessor();
1168 |  |
                     }
1169 | 4 |
                 }
1170 |  |
             }
1171 |  |
1172 | 600000 |
             return sslWritePreProcessor;
1173 |  |
         }
1174 |  |
1175 |  |
         /**
1176 |  |
          * Internal SSL CallbackHandler, which is able to process properly SSL handshake
1177 |  |
          * phase and translate its calls to the custom SSLCallbackHandler.
1178 |  |
          */
1179 | 244 |
         private class SSLInternalCallbackHandler implements CallbackHandler {
1180 |  |
             public void onConnect(IOEvent ioEvent) {
1181 | 122 |
                 callbackHandler.onConnect(ioEvent);
1182 | 122 |
             }
1183 |  |
1184 |  |
             public void onRead(IOEvent ioEvent) {
1185 | 40614 |
                 if (!isAsyncReadQueueMode) {
1186 |  |
                     try {
1187 |  |
                         // if processing handshake - pass the data to handshake related code
1188 | 40614 |
                         if (isProcessingAsyncHandshake) {
1189 | 4 |
                             if (doAsyncHandshake(asyncHandshakeBuffer)) {
1190 | 2 |
                                 callbackHandler.onHandshake(ioEvent);
1191 |  |
                             }
1192 |  |
1193 | 4 |
                             return;
1194 |  |
                         }
1195 |  |
1196 | 40610 |
                         callbackHandler.onRead(ioEvent);
1197 | 0 |
                     } catch (IOException e) {
1198 | 0 |
                         logger.log(Level.SEVERE, "Exception occured when reading from SSL channel.", e);
1199 | 40610 |
                     }
1200 |  |
                 }
1201 | 40610 |
             }
1202 |  |
1203 |  |
             public void onWrite(IOEvent ioEvent) {
1204 | 16 |
                 if (!isAsyncWriteQueueMode) {
1205 |  |
                     try {
1206 |  |
                         // check if all the secured data was written, if not -
1207 |  |
                         // flush as much as possible.
1208 | 0 |
                         if (!securedOutputBuffer.hasRemaining() || flushSecuredOutputBuffer()) {
1209 |  |
                             // if no encrypted data left in buffer - continue processing
1210 | 0 |
                             if (isProcessingAsyncHandshake) {
1211 | 0 |
                                 if (doAsyncHandshake(asyncHandshakeBuffer)) {
1212 | 0 |
                                     callbackHandler.onHandshake(ioEvent);
1213 |  |
                                 }
1214 |  |
1215 | 0 |
                                 return;
1216 |  |
                             }
1217 |  |
1218 | 0 |
                             callbackHandler.onWrite(ioEvent);
1219 |  |
                         }
1220 | 0 |
                     } catch (IOException e) {
1221 | 0 |
                         logger.log(Level.SEVERE, "Exception occured when writing to SSL channel.", e);
1222 | 0 |
                     }
1223 |  |
                 }
1224 | 16 |
             }
1225 |  |
         }
1226 |  |
1227 |  |
         /**
1228 |  |
          * SSL <code>AsyncQueueDataProcessor</code> for a
1229 |  |
          * <code>TCPAsyncQueueReader</code>
1230 |  |
          */
1231 | 2 |
         private class SSLReadPostProcessor implements AsyncQueueDataProcessor {
1232 |  |
             public ByteBuffer getInternalByteBuffer() {
1233 | 150279 |
                 return securedInputBuffer;
1234 |  |
             }
1235 |  |
1236 |  |
             public void process(ByteBuffer byteBuffer) throws SSLException {
1237 | 8569 |
                 securedInputBuffer.flip();
1238 | 8569 |
                 unwrapAll(byteBuffer);
1239 | 8569 |
                 clearOrCompactBuffer(securedInputBuffer);
1240 | 8569 |
             }
1241 |  |
         }
1242 |  |
1243 |  |
         /**
1244 |  |
          * SSL <code>AsyncQueueDataProcessor</code> for a
1245 |  |
          * <code>TCPAsyncQueueWriter</code>
1246 |  |
          */
1247 | 4 |
         private class SSLWritePreProcessor implements AsyncQueueDataProcessor {
1248 |  |
             public ByteBuffer getInternalByteBuffer() {
1249 | 1200000 |
                 return securedOutputBuffer;
1250 |  |
             }
1251 |  |
1252 |  |
             public void process(ByteBuffer byteBuffer) throws SSLException {
1253 | 600000 |
                 if (!byteBuffer.hasRemaining() || securedOutputBuffer.hasRemaining()) return;
1254 |  |
1255 | 600000 |
                 securedOutputBuffer.clear();
1256 | 600000 |
                 SSLEngineResult result = sslEngine.wrap(byteBuffer, securedOutputBuffer);
1257 | 600000 |
                 updateSSLEngineStatus(result);
1258 | 600000 |
                 securedOutputBuffer.flip();
1259 | 600000 |
             }
1260 |  |
         }
1261 |  |
     }