KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > mina > filter > support > SSLHandler


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  *
19  */

20 package org.apache.mina.filter.support;
21
22 import java.nio.ByteBuffer JavaDoc;
23 import java.util.LinkedList JavaDoc;
24 import java.util.Queue JavaDoc;
25 import java.util.concurrent.ConcurrentLinkedQueue JavaDoc;
26
27 import javax.net.ssl.SSLContext;
28 import javax.net.ssl.SSLEngine;
29 import javax.net.ssl.SSLEngineResult;
30 import javax.net.ssl.SSLException;
31 import javax.net.ssl.SSLHandshakeException;
32 import javax.net.ssl.SSLSession;
33
34 import org.apache.mina.common.IoSession;
35 import org.apache.mina.common.WriteFuture;
36 import org.apache.mina.common.IoFilter.NextFilter;
37 import org.apache.mina.common.IoFilter.WriteRequest;
38 import org.apache.mina.common.support.DefaultWriteFuture;
39 import org.apache.mina.filter.SSLFilter;
40 import org.apache.mina.util.SessionLog;
41
42 /**
43  * A helper class using the SSLEngine API to decrypt/encrypt data.
44  * <p>
45  * Each connection has a SSLEngine that is used through the lifetime of the connection.
46  * We allocate byte buffers for use as the outbound and inbound network buffers.
47  * These buffers handle all of the intermediary data for the SSL connection. To make things easy,
48  * we'll require outNetBuffer be completely flushed before trying to wrap any more data.
49  *
50  * @author The Apache Directory Project (mina-dev@directory.apache.org)
51  * @version $Rev: 557169 $, $Date: 2007-07-18 15:26:04 +0900 (수, 18 7월 2007) $
52  */

53 public class SSLHandler {
54     private final SSLFilter parent;
55
56     private final SSLContext ctx;
57
58     private final IoSession session;
59
60     private final Queue JavaDoc<Event> preHandshakeEventQueue = new LinkedList JavaDoc<Event>();
61
62     private final Queue JavaDoc<Event> filterWriteEventQueue = new ConcurrentLinkedQueue JavaDoc<Event>();
63
64     private final Queue JavaDoc<Event> messageReceivedEventQueue = new ConcurrentLinkedQueue JavaDoc<Event>();
65
66     private SSLEngine sslEngine;
67
68     /**
69      * Encrypted data from the net
70      */

71     private ByteBuffer JavaDoc inNetBuffer;
72
73     /**
74      * Encrypted data to be written to the net
75      */

76     private ByteBuffer JavaDoc outNetBuffer;
77
78     /**
79      * Applicaton cleartext data to be read by application
80      */

81     private ByteBuffer JavaDoc appBuffer;
82
83     /**
84      * Empty buffer used during initial handshake and close operations
85      */

86     private final ByteBuffer JavaDoc hsBB = ByteBuffer.allocate(0);
87
88     /**
89      * Handshake status
90      */

91     private SSLEngineResult.HandshakeStatus initialHandshakeStatus;
92
93     /**
94      * Initial handshake complete?
95      */

96     private boolean initialHandshakeComplete;
97
98     private boolean writingEncryptedData;
99
100     /**
101      * Constuctor.
102      *
103      * @param sslc
104      * @throws SSLException
105      */

106     public SSLHandler(SSLFilter parent, SSLContext sslc, IoSession session)
107             throws SSLException {
108         this.parent = parent;
109         this.session = session;
110         this.ctx = sslc;
111         init();
112     }
113
114     public void init() throws SSLException {
115         if (sslEngine != null) {
116             return;
117         }
118
119         sslEngine = ctx.createSSLEngine();
120         sslEngine.setUseClientMode(parent.isUseClientMode());
121
122         if (parent.isWantClientAuth()) {
123             sslEngine.setWantClientAuth(true);
124         }
125
126         if (parent.isNeedClientAuth()) {
127             sslEngine.setNeedClientAuth(true);
128         }
129
130         if (parent.getEnabledCipherSuites() != null) {
131             sslEngine.setEnabledCipherSuites(parent.getEnabledCipherSuites());
132         }
133
134         if (parent.getEnabledProtocols() != null) {
135             sslEngine.setEnabledProtocols(parent.getEnabledProtocols());
136         }
137
138         sslEngine.beginHandshake();
139         initialHandshakeStatus = sslEngine.getHandshakeStatus();//SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
140
initialHandshakeComplete = false;
141
142         SSLByteBufferPool.initiate(sslEngine);
143
144         appBuffer = SSLByteBufferPool.getApplicationBuffer();
145
146         inNetBuffer = SSLByteBufferPool.getPacketBuffer();
147         outNetBuffer = SSLByteBufferPool.getPacketBuffer();
148         outNetBuffer.position(0);
149         outNetBuffer.limit(0);
150
151         writingEncryptedData = false;
152     }
153
154     /**
155      * Release allocated ByteBuffers.
156      */

157     public void destroy() {
158         if (sslEngine == null) {
159             return;
160         }
161
162         // Close inbound and flush all remaining data if available.
163
try {
164             sslEngine.closeInbound();
165         } catch (SSLException e) {
166             SessionLog.debug(session,
167                     "Unexpected exception from SSLEngine.closeInbound().", e);
168         }
169
170         try {
171             do {
172                 outNetBuffer.clear();
173             } while (sslEngine.wrap(hsBB, outNetBuffer).bytesProduced() > 0);
174         } catch (SSLException e) {
175             SessionLog.debug(session,
176                     "Unexpected exception from SSLEngine.wrap().", e);
177         }
178         sslEngine.closeOutbound();
179         sslEngine = null;
180
181         SSLByteBufferPool.release(appBuffer);
182         SSLByteBufferPool.release(inNetBuffer);
183         SSLByteBufferPool.release(outNetBuffer);
184         preHandshakeEventQueue.clear();
185         //postHandshakeEventQueue.clear();
186
}
187
188     public SSLFilter getParent() {
189         return parent;
190     }
191
192     public IoSession getSession() {
193         return session;
194     }
195
196     /**
197      * Check we are writing encrypted data.
198      */

199     public boolean isWritingEncryptedData() {
200         return writingEncryptedData;
201     }
202
203     /**
204      * Check if initial handshake is completed.
205      */

206     public boolean isInitialHandshakeComplete() {
207         return initialHandshakeComplete;
208     }
209
210     public boolean isInboundDone() {
211         return sslEngine == null || sslEngine.isInboundDone();
212     }
213
214     public boolean isOutboundDone() {
215         return sslEngine == null || sslEngine.isOutboundDone();
216     }
217
218     /**
219      * Check if there is any need to complete initial handshake.
220      */

221     public boolean needToCompleteInitialHandshake() {
222         return (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP && !isInboundDone());
223     }
224
225     public void schedulePreHandshakeWriteRequest(NextFilter nextFilter,
226             WriteRequest writeRequest) {
227         preHandshakeEventQueue.offer(new Event(EventType.FILTER_WRITE,
228                 nextFilter, writeRequest));
229     }
230
231     public void flushPreHandshakeEvents() throws SSLException {
232         Event scheduledWrite;
233
234         while ((scheduledWrite = preHandshakeEventQueue.poll()) != null) {
235             if (SessionLog.isDebugEnabled(session)) {
236                 SessionLog.debug(session, " Flushing buffered write request: "
237                         + scheduledWrite.data);
238             }
239             parent.filterWrite(scheduledWrite.nextFilter, session,
240                     (WriteRequest) scheduledWrite.data);
241         }
242     }
243
244     public void scheduleFilterWrite(NextFilter nextFilter,
245             WriteRequest writeRequest) {
246         filterWriteEventQueue.offer(new Event(EventType.FILTER_WRITE,
247                 nextFilter, writeRequest));
248     }
249
250     public void scheduleMessageReceived(NextFilter nextFilter,
251             Object JavaDoc message) {
252         messageReceivedEventQueue.offer(new Event(EventType.RECEIVED, nextFilter,
253                 message));
254     }
255     
256     public void flushScheduledEvents() {
257         // Fire events only when no lock is hold for this handler.
258
if (Thread.holdsLock(this)) {
259             return;
260         }
261
262         Event e;
263         
264         // We need synchronization here inevitably because filterWrite can be
265
// called simultaneously and cause 'bad record MAC' integrity error.
266
synchronized (this) {
267             while ((e = filterWriteEventQueue.poll()) != null) {
268                 e.nextFilter.filterWrite(session, (WriteRequest) e.data);
269             }
270         }
271
272         while ((e = messageReceivedEventQueue.poll()) != null) {
273             e.nextFilter.messageReceived(session, e.data);
274         }
275     }
276
277     /**
278      * Call when data read from net. Will perform inial hanshake or decrypt provided
279      * Buffer.
280      * Decrytpted data reurned by getAppBuffer(), if any.
281      *
282      * @param buf buffer to decrypt
283      * @throws SSLException on errors
284      */

285     public void messageReceived(NextFilter nextFilter, ByteBuffer JavaDoc buf)
286             throws SSLException {
287         if (buf.limit() > inNetBuffer.remaining()) {
288             // We have to expand inNetBuffer
289
inNetBuffer = SSLByteBufferPool.expandBuffer(inNetBuffer,
290                     inNetBuffer.capacity() + (buf.limit() * 2));
291             // We also expand app. buffer (twice the size of in net. buffer)
292
appBuffer = SSLByteBufferPool.expandBuffer(appBuffer, inNetBuffer
293                     .capacity() * 2);
294             appBuffer.position(0);
295             appBuffer.limit(0);
296             if (SessionLog.isDebugEnabled(session)) {
297                 SessionLog.debug(session, " expanded inNetBuffer:"
298                         + inNetBuffer);
299                 SessionLog.debug(session, " expanded appBuffer:" + appBuffer);
300             }
301         }
302
303         // append buf to inNetBuffer
304
inNetBuffer.put(buf);
305         if (!initialHandshakeComplete) {
306             handshake(nextFilter);
307         } else {
308             decrypt();
309         }
310
311         if (isInboundDone()) {
312             // Rewind the MINA buffer if not all data is processed and inbound is finished.
313
buf.position(buf.position() - inNetBuffer.position());
314             inNetBuffer.clear();
315         }
316     }
317
318     /**
319      * Get decrypted application data.
320      *
321      * @return buffer with data
322      */

323     public ByteBuffer JavaDoc getAppBuffer() {
324         return appBuffer;
325     }
326
327     /**
328      * Get encrypted data to be sent.
329      *
330      * @return buffer with data
331      */

332     public ByteBuffer JavaDoc getOutNetBuffer() {
333         return outNetBuffer;
334     }
335
336     /**
337      * Encrypt provided buffer. Encytpted data reurned by getOutNetBuffer().
338      *
339      * @param src data to encrypt
340      * @throws SSLException on errors
341      */

342     public void encrypt(ByteBuffer JavaDoc src) throws SSLException {
343         if (!initialHandshakeComplete) {
344             throw new IllegalStateException JavaDoc();
345         }
346
347         // The data buffer is (must be) empty, we can reuse the entire
348
// buffer.
349
outNetBuffer.clear();
350
351         // Loop until there is no more data in src
352
while (src.hasRemaining()) {
353
354             if (src.remaining() > ((outNetBuffer.capacity() - outNetBuffer
355                     .position()) / 2)) {
356                 // We have to expand outNetBuffer
357
// Note: there is no way to know the exact size required, but enrypted data
358
// shouln't need to be larger than twice the source data size?
359
outNetBuffer = SSLByteBufferPool.expandBuffer(outNetBuffer, src
360                         .capacity() * 2);
361                 if (SessionLog.isDebugEnabled(session)) {
362                     SessionLog.debug(session, " expanded outNetBuffer:"
363                             + outNetBuffer);
364                 }
365             }
366
367             SSLEngineResult result = sslEngine.wrap(src, outNetBuffer);
368             if (SessionLog.isDebugEnabled(session)) {
369                 SessionLog.debug(session, " Wrap res:" + result);
370             }
371
372             if (result.getStatus() == SSLEngineResult.Status.OK) {
373                 if (result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK) {
374                     doTasks();
375                 }
376             } else {
377                 throw new SSLException("SSLEngine error during encrypt: "
378                         + result.getStatus() + " src: " + src
379                         + "outNetBuffer: " + outNetBuffer);
380             }
381         }
382
383         outNetBuffer.flip();
384     }
385
386     /**
387      * Start SSL shutdown process.
388      *
389      * @return <tt>true</tt> if shutdown process is started.
390      * <tt>false</tt> if shutdown process is already finished.
391      *
392      * @throws SSLException on errors
393      */

394     public boolean closeOutbound() throws SSLException {
395         if (sslEngine == null || sslEngine.isOutboundDone()) {
396             return false;
397         }
398
399         sslEngine.closeOutbound();
400
401         // By RFC 2616, we can "fire and forget" our close_notify
402
// message, so that's what we'll do here.
403
outNetBuffer.clear();
404         SSLEngineResult result = sslEngine.wrap(hsBB, outNetBuffer);
405         if (result.getStatus() != SSLEngineResult.Status.CLOSED) {
406             throw new SSLException("Improper close state: " + result);
407         }
408         outNetBuffer.flip();
409         return true;
410     }
411
412     /**
413      * Decrypt in net buffer. Result is stored in app buffer.
414      *
415      * @throws SSLException
416      */

417     private void decrypt() throws SSLException {
418
419         if (!initialHandshakeComplete) {
420             throw new IllegalStateException JavaDoc();
421         }
422
423         if (appBuffer.hasRemaining()) {
424             if (SessionLog.isDebugEnabled(session)) {
425                 SessionLog.debug(session, " Error: appBuffer not empty!");
426             }
427             //still app data in buffer!?
428
throw new IllegalStateException JavaDoc();
429         }
430
431         unwrap();
432     }
433
434     /**
435      * @param status
436      * @throws SSLException
437      */

438     private SSLEngineResult.Status checkStatus(SSLEngineResult.Status status)
439             throws SSLException {
440         if (status != SSLEngineResult.Status.OK
441                 && status != SSLEngineResult.Status.CLOSED
442                 && status != SSLEngineResult.Status.BUFFER_UNDERFLOW) {
443             throw new SSLException("SSLEngine error during decrypt: " + status
444                     + " inNetBuffer: " + inNetBuffer + "appBuffer: "
445                     + appBuffer);
446         }
447
448         return status;
449     }
450
451     /**
452      * Perform any handshaking processing.
453      */

454     public void handshake(NextFilter nextFilter) throws SSLException {
455         if (SessionLog.isDebugEnabled(session)) {
456             SessionLog.debug(session, " doHandshake()");
457         }
458
459         while (!initialHandshakeComplete) {
460             if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED) {
461                 session.setAttribute(SSLFilter.SSL_SESSION, sslEngine
462                         .getSession());
463                 if (SessionLog.isDebugEnabled(session)) {
464                     SSLSession sslSession = sslEngine.getSession();
465                     SessionLog.debug(session,
466                             " initialHandshakeStatus=FINISHED");
467                     SessionLog.debug(session, " sslSession CipherSuite used "
468                             + sslSession.getCipherSuite());
469                 }
470                 initialHandshakeComplete = true;
471                 if (session.containsAttribute(SSLFilter.USE_NOTIFICATION)) {
472                     scheduleMessageReceived(nextFilter,
473                             SSLFilter.SESSION_SECURED);
474                 }
475                 break;
476             } else if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_TASK) {
477                 if (SessionLog.isDebugEnabled(session)) {
478                     SessionLog.debug(session,
479                             " initialHandshakeStatus=NEED_TASK");
480                 }
481                 initialHandshakeStatus = doTasks();
482             } else if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_UNWRAP) {
483                 // we need more data read
484
if (SessionLog.isDebugEnabled(session)) {
485                     SessionLog.debug(session,
486                             " initialHandshakeStatus=NEED_UNWRAP");
487                 }
488                 SSLEngineResult.Status status = unwrapHandshake();
489                 if ((initialHandshakeStatus != SSLEngineResult.HandshakeStatus.FINISHED && status == SSLEngineResult.Status.BUFFER_UNDERFLOW)
490                         || isInboundDone()) {
491                     // We need more data or the session is closed
492
break;
493                 }
494             } else if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP) {
495                 if (SessionLog.isDebugEnabled(session)) {
496                     SessionLog.debug(session,
497                             " initialHandshakeStatus=NEED_WRAP");
498                 }
499                 // First make sure that the out buffer is completely empty. Since we
500
// cannot call wrap with data left on the buffer
501
if (outNetBuffer.hasRemaining()) {
502                     if (SessionLog.isDebugEnabled(session)) {
503                         SessionLog
504                                 .debug(session, " Still data in out buffer!");
505                     }
506                     break;
507                 }
508                 outNetBuffer.clear();
509                 SSLEngineResult result = sslEngine.wrap(hsBB, outNetBuffer);
510                 if (SessionLog.isDebugEnabled(session)) {
511                     SessionLog.debug(session, " Wrap res:" + result);
512                 }
513
514                 outNetBuffer.flip();
515                 initialHandshakeStatus = result.getHandshakeStatus();
516                 writeNetBuffer(nextFilter);
517             } else {
518                 throw new IllegalStateException JavaDoc("Invalid Handshaking State"
519                         + initialHandshakeStatus);
520             }
521         }
522     }
523
524     public WriteFuture writeNetBuffer(NextFilter nextFilter)
525             throws SSLException {
526         // Check if any net data needed to be writen
527
if (!getOutNetBuffer().hasRemaining()) {
528             // no; bail out
529
return DefaultWriteFuture.newNotWrittenFuture(session);
530         }
531
532         // set flag that we are writing encrypted data
533
// (used in SSLFilter.filterWrite())
534
writingEncryptedData = true;
535
536         // write net data
537
WriteFuture writeFuture = null;
538
539         try {
540             if (SessionLog.isDebugEnabled(session)) {
541                 SessionLog.debug(session, " write outNetBuffer: "
542                         + getOutNetBuffer());
543             }
544             org.apache.mina.common.ByteBuffer writeBuffer = copy(getOutNetBuffer());
545             if (SessionLog.isDebugEnabled(session)) {
546                 SessionLog.debug(session, " session write: " + writeBuffer);
547             }
548             //debug("outNetBuffer (after copy): {0}", sslHandler.getOutNetBuffer());
549

550             writeFuture = new DefaultWriteFuture(session);
551             parent.filterWrite(nextFilter, session, new WriteRequest(
552                     writeBuffer, writeFuture));
553
554             // loop while more writes required to complete handshake
555
while (needToCompleteInitialHandshake()) {
556                 try {
557                     handshake(nextFilter);
558                 } catch (SSLException ssle) {
559                     SSLException newSSLE = new SSLHandshakeException(
560                             "Initial SSL handshake failed.");
561                     newSSLE.initCause(ssle);
562                     throw newSSLE;
563                 }
564                 if (getOutNetBuffer().hasRemaining()) {
565                     if (SessionLog.isDebugEnabled(session)) {
566                         SessionLog.debug(session, " write outNetBuffer2: "
567                                 + getOutNetBuffer());
568                     }
569                     org.apache.mina.common.ByteBuffer writeBuffer2 = copy(getOutNetBuffer());
570                     writeFuture = new DefaultWriteFuture(session);
571                     parent.filterWrite(nextFilter, session, new WriteRequest(
572                             writeBuffer2, writeFuture));
573                 }
574             }
575         } finally {
576             writingEncryptedData = false;
577         }
578
579         return writeFuture;
580     }
581
582     private SSLEngineResult.Status unwrap() throws SSLException {
583         if (SessionLog.isDebugEnabled(session)) {
584             SessionLog.debug(session, " unwrap()");
585         }
586         // Prepare the application buffer to receive decrypted data
587
appBuffer.clear();
588
589         // Prepare the net data for reading.
590
inNetBuffer.flip();
591
592         SSLEngineResult res;
593         do {
594             if (SessionLog.isDebugEnabled(session)) {
595                 SessionLog.debug(session, " inNetBuffer: " + inNetBuffer);
596                 SessionLog.debug(session, " appBuffer: " + appBuffer);
597             }
598             res = sslEngine.unwrap(inNetBuffer, appBuffer);
599             if (SessionLog.isDebugEnabled(session)) {
600                 SessionLog.debug(session, " Unwrap res:" + res);
601             }
602         } while (res.getStatus() == SSLEngineResult.Status.OK);
603
604         // prepare to be written again
605
inNetBuffer.compact();
606         // prepare app data to be read
607
appBuffer.flip();
608
609         /*
610          * The status may be:
611          * OK - Normal operation
612          * OVERFLOW - Should never happen since the application buffer is
613          * sized to hold the maximum packet size.
614          * UNDERFLOW - Need to read more data from the socket. It's normal.
615          * CLOSED - The other peer closed the socket. Also normal.
616          */

617         return checkStatus(res.getStatus());
618     }
619
620     private SSLEngineResult.Status unwrapHandshake() throws SSLException {
621         if (SessionLog.isDebugEnabled(session)) {
622             SessionLog.debug(session, " unwrapHandshake()");
623         }
624         // Prepare the application buffer to receive decrypted data
625
appBuffer.clear();
626
627         // Prepare the net data for reading.
628
inNetBuffer.flip();
629
630         SSLEngineResult res;
631         do {
632             if (SessionLog.isDebugEnabled(session)) {
633                 SessionLog.debug(session, " inNetBuffer: " + inNetBuffer);
634                 SessionLog.debug(session, " appBuffer: " + appBuffer);
635             }
636             res = sslEngine.unwrap(inNetBuffer, appBuffer);
637             if (SessionLog.isDebugEnabled(session)) {
638                 SessionLog.debug(session, " Unwrap res:" + res);
639             }
640
641         } while (res.getStatus() == SSLEngineResult.Status.OK
642                 && res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_UNWRAP);
643
644         initialHandshakeStatus = res.getHandshakeStatus();
645
646         // If handshake finished, no data was produced, and the status is still ok,
647
// try to unwrap more
648
if (initialHandshakeStatus == SSLEngineResult.HandshakeStatus.FINISHED
649                 && appBuffer.position() == 0
650                 && res.getStatus() == SSLEngineResult.Status.OK
651                 && inNetBuffer.hasRemaining()) {
652             do {
653                 if (SessionLog.isDebugEnabled(session)) {
654                     SessionLog.debug(session, " extra handshake unwrap");
655                     SessionLog.debug(session, " inNetBuffer: " + inNetBuffer);
656                     SessionLog.debug(session, " appBuffer: " + appBuffer);
657                 }
658                 res = sslEngine.unwrap(inNetBuffer, appBuffer);
659                 if (SessionLog.isDebugEnabled(session)) {
660                     SessionLog.debug(session, " Unwrap res:" + res);
661                 }
662             } while (res.getStatus() == SSLEngineResult.Status.OK);
663         }
664
665         // prepare to be written again
666
inNetBuffer.compact();
667
668         // prepare app data to be read
669
appBuffer.flip();
670
671         /*
672          * The status may be:
673          * OK - Normal operation
674          * OVERFLOW - Should never happen since the application buffer is
675          * sized to hold the maximum packet size.
676          * UNDERFLOW - Need to read more data from the socket. It's normal.
677          * CLOSED - The other peer closed the socket. Also normal.
678          */

679         //initialHandshakeStatus = res.getHandshakeStatus();
680
return checkStatus(res.getStatus());
681     }
682
683     /**
684      * Do all the outstanding handshake tasks in the current Thread.
685      */

686     private SSLEngineResult.HandshakeStatus doTasks() {
687         if (SessionLog.isDebugEnabled(session)) {
688             SessionLog.debug(session, " doTasks()");
689         }
690
691         /*
692          * We could run this in a separate thread, but I don't see the need
693          * for this when used from SSLFilter. Use thread filters in MINA instead?
694          */

695         Runnable JavaDoc runnable;
696         while ((runnable = sslEngine.getDelegatedTask()) != null) {
697             if (SessionLog.isDebugEnabled(session)) {
698                 SessionLog.debug(session, " doTask: " + runnable);
699             }
700             runnable.run();
701         }
702         if (SessionLog.isDebugEnabled(session)) {
703             SessionLog.debug(session, " doTasks(): "
704                     + sslEngine.getHandshakeStatus());
705         }
706         return sslEngine.getHandshakeStatus();
707     }
708
709     /**
710      * Creates a new Mina byte buffer that is a deep copy of the remaining bytes
711      * in the given buffer (between index buf.position() and buf.limit())
712      *
713      * @param src the buffer to copy
714      * @return the new buffer, ready to read from
715      */

716     public static org.apache.mina.common.ByteBuffer copy(java.nio.ByteBuffer JavaDoc src) {
717         org.apache.mina.common.ByteBuffer copy = org.apache.mina.common.ByteBuffer
718                 .allocate(src.remaining());
719         copy.put(src);
720         copy.flip();
721         return copy;
722     }
723
724     private static class EventType {
725         public static final EventType RECEIVED = new EventType("RECEIVED");
726
727         public static final EventType FILTER_WRITE = new EventType(
728                 "FILTER_WRITE");
729
730         private final String JavaDoc value;
731
732         private EventType(String JavaDoc value) {
733             this.value = value;
734         }
735
736         public String JavaDoc toString() {
737             return value;
738         }
739     }
740
741     private static class Event {
742         private final EventType type;
743
744         private final NextFilter nextFilter;
745
746         private final Object JavaDoc data;
747
748         Event(EventType type, NextFilter nextFilter, Object JavaDoc data) {
749             this.type = type;
750             this.nextFilter = nextFilter;
751             this.data = data;
752         }
753
754         public Object JavaDoc getData() {
755             return data;
756         }
757
758         public NextFilter getNextFilter() {
759             return nextFilter;
760         }
761
762         public EventType getType() {
763             return type;
764         }
765     }
766 }
767
Popular Tags