Source Code Cross Referenced for SslFilter.java in  » Net » mina-2.0.0-M1 » org » apache » mina » filter » ssl » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Net » mina 2.0.0 M1 » org.apache.mina.filter.ssl 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         *  Licensed to the Apache Software Foundation (ASF) under one
003:         *  or more contributor license agreements.  See the NOTICE file
004:         *  distributed with this work for additional information
005:         *  regarding copyright ownership.  The ASF licenses this file
006:         *  to you under the Apache License, Version 2.0 (the
007:         *  "License"); you may not use this file except in compliance
008:         *  with the License.  You may obtain a copy of the License at
009:         *
010:         *    http://www.apache.org/licenses/LICENSE-2.0
011:         *
012:         *  Unless required by applicable law or agreed to in writing,
013:         *  software distributed under the License is distributed on an
014:         *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015:         *  KIND, either express or implied.  See the License for the
016:         *  specific language governing permissions and limitations
017:         *  under the License.
018:         *
019:         */
020:        package org.apache.mina.filter.ssl;
021:
022:        import java.net.InetSocketAddress;
023:        import java.util.ArrayList;
024:        import java.util.List;
025:
026:        import javax.net.ssl.SSLContext;
027:        import javax.net.ssl.SSLEngine;
028:        import javax.net.ssl.SSLException;
029:        import javax.net.ssl.SSLHandshakeException;
030:        import javax.net.ssl.SSLSession;
031:
032:        import org.apache.mina.common.AttributeKey;
033:        import org.apache.mina.common.DefaultWriteFuture;
034:        import org.apache.mina.common.IoBuffer;
035:        import org.apache.mina.common.IoFilterAdapter;
036:        import org.apache.mina.common.IoFilterChain;
037:        import org.apache.mina.common.IoFuture;
038:        import org.apache.mina.common.IoFutureListener;
039:        import org.apache.mina.common.IoHandler;
040:        import org.apache.mina.common.IoSession;
041:        import org.apache.mina.common.WriteFuture;
042:        import org.apache.mina.common.WriteRequest;
043:        import org.apache.mina.common.WriteRequestWrapper;
044:        import org.apache.mina.common.WriteToClosedSessionException;
045:
046:        /**
047:         * An SSL filter that encrypts and decrypts the data exchanged in the session.
048:         * Adding this filter triggers SSL handshake procedure immediately by sending
049:         * a SSL 'hello' message, so you don't need to call
050:         * {@link #startSsl(IoSession)} manually unless you are implementing StartTLS
051:         * (see below).  If you don't want the handshake procedure to start
052:         * immediately, please specify {@code true} as {@code autoStart} parameter in
053:         * the constructor.
054:         * <p>
055:         * This filter uses an {@link SSLEngine} which was introduced in Java 5, so
056:         * Java version 5 or above is mandatory to use this filter. And please note that
057:         * this filter only works for TCP/IP connections.
058:         * <p>
059:         *
060:         * <h2>Implementing StartTLS</h2>
061:         * <p>
062:         * You can use {@link #DISABLE_ENCRYPTION_ONCE} attribute to implement StartTLS:
063:         * <pre>
064:         * public void messageReceived(IoSession session, Object message) {
065:         *    if (message instanceof MyStartTLSRequest) {
066:         *        // Insert SSLFilter to get ready for handshaking
067:         *        session.getFilterChain().addFirst(sslFilter);
068:         *
069:         *        // Disable encryption temporarilly.
070:         *        // This attribute will be removed by SSLFilter
071:         *        // inside the Session.write() call below.
072:         *        session.setAttribute(SSLFilter.DISABLE_ENCRYPTION_ONCE, Boolean.TRUE);
073:         *
074:         *        // Write StartTLSResponse which won't be encrypted.
075:         *        session.write(new MyStartTLSResponse(OK));
076:         *
077:         *        // Now DISABLE_ENCRYPTION_ONCE attribute is cleared.
078:         *        assert session.getAttribute(SSLFilter.DISABLE_ENCRYPTION_ONCE) == null;
079:         *    }
080:         * }
081:         * </pre>
082:         *
083:         * @author The Apache MINA Project (dev@mina.apache.org)
084:         * @version $Rev: 616100 $, $Date: 2008-01-28 15:58:32 -0700 (Mon, 28 Jan 2008) $
085:         */
086:        public class SslFilter extends IoFilterAdapter {
087:            /**
088:             * A session attribute key that stores underlying {@link SSLSession}
089:             * for each session.
090:             */
091:            public static final AttributeKey SSL_SESSION = new AttributeKey(
092:                    SslFilter.class, "session");
093:
094:            /**
095:             * A session attribute key that makes next one write request bypass
096:             * this filter (not encrypting the data).  This is a marker attribute,
097:             * which means that you can put whatever as its value. ({@link Boolean#TRUE}
098:             * is preferred.)  The attribute is automatically removed from the session
099:             * attribute map as soon as {@link IoSession#write(Object)} is invoked,
100:             * and therefore should be put again if you want to make more messages
101:             * bypass this filter.  This is especially useful when you implement
102:             * StartTLS.
103:             */
104:            public static final AttributeKey DISABLE_ENCRYPTION_ONCE = new AttributeKey(
105:                    SslFilter.class, "disableOnce");
106:
107:            /**
108:             * A session attribute key that makes this filter to emit a
109:             * {@link IoHandler#messageReceived(IoSession, Object)} event with a
110:             * special message ({@link #SESSION_SECURED} or {@link #SESSION_UNSECURED}).
111:             * This is a marker attribute, which means that you can put whatever as its
112:             * value. ({@link Boolean#TRUE} is preferred.)  By default, this filter
113:             * doesn't emit any events related with SSL session flow control.
114:             */
115:            public static final AttributeKey USE_NOTIFICATION = new AttributeKey(
116:                    SslFilter.class, "useNotification");
117:
118:            /**
119:             * A session attribute key that should be set to an {@link InetSocketAddress}.
120:             * Setting this attribute causes
121:             * {@link SSLContext#createSSLEngine(String, int)} to be called passing the
122:             * hostname and port of the {@link InetSocketAddress} to get an
123:             * {@link SSLEngine} instance. If not set {@link SSLContext#createSSLEngine()}
124:             * will be called.
125:             * .
126:             * Using this feature {@link SSLSession} objects may be cached and reused
127:             * when in client mode.
128:             *
129:             * @see SSLContext#createSSLEngine(String, int)
130:             */
131:            public static final AttributeKey PEER_ADDRESS = new AttributeKey(
132:                    SslFilter.class, "peerAddress");
133:
134:            /**
135:             * A special message object which is emitted with a {@link IoHandler#messageReceived(IoSession, Object)}
136:             * event when the session is secured and its {@link #USE_NOTIFICATION}
137:             * attribute is set.
138:             */
139:            public static final SslFilterMessage SESSION_SECURED = new SslFilterMessage(
140:                    "SESSION_SECURED");
141:
142:            /**
143:             * A special message object which is emitted with a {@link IoHandler#messageReceived(IoSession, Object)}
144:             * event when the session is not secure anymore and its {@link #USE_NOTIFICATION}
145:             * attribute is set.
146:             */
147:            public static final SslFilterMessage SESSION_UNSECURED = new SslFilterMessage(
148:                    "SESSION_UNSECURED");
149:
150:            private static final AttributeKey NEXT_FILTER = new AttributeKey(
151:                    SslFilter.class, "nextFilter");
152:            private static final AttributeKey SSL_HANDLER = new AttributeKey(
153:                    SslFilter.class, "handler");
154:
155:            // SSL Context
156:            private final SSLContext sslContext;
157:
158:            private final boolean autoStart;
159:
160:            private boolean client;
161:
162:            private boolean needClientAuth;
163:
164:            private boolean wantClientAuth;
165:
166:            private String[] enabledCipherSuites;
167:
168:            private String[] enabledProtocols;
169:
170:            /**
171:             * Creates a new SSL filter using the specified {@link SSLContext}.
172:             */
173:            public SslFilter(SSLContext sslContext) {
174:                this (sslContext, true);
175:            }
176:
177:            /**
178:             * Creates a new SSL filter using the specified {@link SSLContext}.
179:             */
180:            public SslFilter(SSLContext sslContext, boolean autoStart) {
181:                if (sslContext == null) {
182:                    throw new NullPointerException("sslContext");
183:                }
184:
185:                this .sslContext = sslContext;
186:                this .autoStart = autoStart;
187:            }
188:
189:            /**
190:             * Returns the underlying {@link SSLSession} for the specified session.
191:             *
192:             * @return <tt>null</tt> if no {@link SSLSession} is initialized yet.
193:             */
194:            public SSLSession getSslSession(IoSession session) {
195:                return (SSLSession) session.getAttribute(SSL_SESSION);
196:            }
197:
198:            /**
199:             * (Re)starts SSL session for the specified <tt>session</tt> if not started yet.
200:             * Please note that SSL session is automatically started by default, and therefore
201:             * you don't need to call this method unless you've used TLS closure.
202:             *
203:             * @return <tt>true</tt> if the SSL session has been started, <tt>false</tt> if already started.
204:             * @throws SSLException if failed to start the SSL session
205:             */
206:            public boolean startSsl(IoSession session) throws SSLException {
207:                SslHandler handler = getSslSessionHandler(session);
208:                boolean started;
209:                synchronized (handler) {
210:                    if (handler.isOutboundDone()) {
211:                        NextFilter nextFilter = (NextFilter) session
212:                                .getAttribute(NEXT_FILTER);
213:                        handler.destroy();
214:                        handler.init();
215:                        handler.handshake(nextFilter);
216:                        started = true;
217:                    } else {
218:                        started = false;
219:                    }
220:                }
221:
222:                handler.flushScheduledEvents();
223:                return started;
224:            }
225:
226:            /**
227:             * Returns <tt>true</tt> if and only if the specified <tt>session</tt> is
228:             * encrypted/decrypted over SSL/TLS currently.  This method will start
229:             * to retun <tt>false</tt> after TLS <tt>close_notify</tt> message
230:             * is sent and any messages written after then is not goinf to get encrypted.
231:             */
232:            public boolean isSslStarted(IoSession session) {
233:                SslHandler handler = getSslSessionHandler0(session);
234:                if (handler == null) {
235:                    return false;
236:                }
237:
238:                synchronized (handler) {
239:                    return !handler.isOutboundDone();
240:                }
241:            }
242:
243:            /**
244:             * Stops the SSL session by sending TLS <tt>close_notify</tt> message to
245:             * initiate TLS closure.
246:             *
247:             * @param session the {@link IoSession} to initiate TLS closure
248:             * @throws SSLException if failed to initiate TLS closure
249:             * @throws IllegalArgumentException if this filter is not managing the specified session
250:             */
251:            public WriteFuture stopSsl(IoSession session) throws SSLException {
252:                SslHandler handler = getSslSessionHandler(session);
253:                NextFilter nextFilter = (NextFilter) session
254:                        .getAttribute(NEXT_FILTER);
255:                WriteFuture future;
256:                synchronized (handler) {
257:                    future = initiateClosure(nextFilter, session);
258:                }
259:
260:                handler.flushScheduledEvents();
261:
262:                return future;
263:            }
264:
265:            /**
266:             * Returns <tt>true</tt> if the engine is set to use client mode
267:             * when handshaking.
268:             */
269:            public boolean isUseClientMode() {
270:                return client;
271:            }
272:
273:            /**
274:             * Configures the engine to use client (or server) mode when handshaking.
275:             */
276:            public void setUseClientMode(boolean clientMode) {
277:                this .client = clientMode;
278:            }
279:
280:            /**
281:             * Returns <tt>true</tt> if the engine will <em>require</em> client authentication.
282:             * This option is only useful to engines in the server mode.
283:             */
284:            public boolean isNeedClientAuth() {
285:                return needClientAuth;
286:            }
287:
288:            /**
289:             * Configures the engine to <em>require</em> client authentication.
290:             * This option is only useful for engines in the server mode.
291:             */
292:            public void setNeedClientAuth(boolean needClientAuth) {
293:                this .needClientAuth = needClientAuth;
294:            }
295:
296:            /**
297:             * Returns <tt>true</tt> if the engine will <em>request</em> client authentication.
298:             * This option is only useful to engines in the server mode.
299:             */
300:            public boolean isWantClientAuth() {
301:                return wantClientAuth;
302:            }
303:
304:            /**
305:             * Configures the engine to <em>request</em> client authentication.
306:             * This option is only useful for engines in the server mode.
307:             */
308:            public void setWantClientAuth(boolean wantClientAuth) {
309:                this .wantClientAuth = wantClientAuth;
310:            }
311:
312:            /**
313:             * Returns the list of cipher suites to be enabled when {@link SSLEngine}
314:             * is initialized.
315:             *
316:             * @return <tt>null</tt> means 'use {@link SSLEngine}'s default.'
317:             */
318:            public String[] getEnabledCipherSuites() {
319:                return enabledCipherSuites;
320:            }
321:
322:            /**
323:             * Sets the list of cipher suites to be enabled when {@link SSLEngine}
324:             * is initialized.
325:             *
326:             * @param cipherSuites <tt>null</tt> means 'use {@link SSLEngine}'s default.'
327:             */
328:            public void setEnabledCipherSuites(String[] cipherSuites) {
329:                this .enabledCipherSuites = cipherSuites;
330:            }
331:
332:            /**
333:             * Returns the list of protocols to be enabled when {@link SSLEngine}
334:             * is initialized.
335:             *
336:             * @return <tt>null</tt> means 'use {@link SSLEngine}'s default.'
337:             */
338:            public String[] getEnabledProtocols() {
339:                return enabledProtocols;
340:            }
341:
342:            /**
343:             * Sets the list of protocols to be enabled when {@link SSLEngine}
344:             * is initialized.
345:             *
346:             * @param protocols <tt>null</tt> means 'use {@link SSLEngine}'s default.'
347:             */
348:            public void setEnabledProtocols(String[] protocols) {
349:                this .enabledProtocols = protocols;
350:            }
351:
352:            @Override
353:            public void onPreAdd(IoFilterChain parent, String name,
354:                    NextFilter nextFilter) throws SSLException {
355:                if (parent.contains(SslFilter.class)) {
356:                    throw new IllegalStateException("Only one "
357:                            + SslFilter.class.getName() + " is permitted.");
358:                }
359:
360:                IoSession session = parent.getSession();
361:                session.setAttribute(NEXT_FILTER, nextFilter);
362:
363:                // Create an SSL handler and start handshake.
364:                SslHandler handler = new SslHandler(this , sslContext, session);
365:                session.setAttribute(SSL_HANDLER, handler);
366:            }
367:
368:            @Override
369:            public void onPostAdd(IoFilterChain parent, String name,
370:                    NextFilter nextFilter) throws SSLException {
371:                if (autoStart) {
372:                    initiateHandshake(nextFilter, parent.getSession());
373:                }
374:            }
375:
376:            @Override
377:            public void onPreRemove(IoFilterChain parent, String name,
378:                    NextFilter nextFilter) throws SSLException {
379:                IoSession session = parent.getSession();
380:                stopSsl(session);
381:                session.removeAttribute(NEXT_FILTER);
382:                session.removeAttribute(SSL_HANDLER);
383:            }
384:
385:            // IoFilter impl.
386:            @Override
387:            public void sessionClosed(NextFilter nextFilter, IoSession session)
388:                    throws SSLException {
389:                SslHandler handler = getSslSessionHandler(session);
390:                try {
391:                    synchronized (handler) {
392:                        // release resources
393:                        handler.destroy();
394:                    }
395:
396:                    handler.flushScheduledEvents();
397:                } finally {
398:                    // notify closed session
399:                    nextFilter.sessionClosed(session);
400:                }
401:            }
402:
403:            @Override
404:            public void messageReceived(NextFilter nextFilter,
405:                    IoSession session, Object message) throws SSLException {
406:                SslHandler handler = getSslSessionHandler(session);
407:                synchronized (handler) {
408:                    if (!isSslStarted(session) && handler.isInboundDone()) {
409:                        handler.scheduleMessageReceived(nextFilter, message);
410:                    } else {
411:                        IoBuffer buf = (IoBuffer) message;
412:                        try {
413:                            // forward read encrypted data to SSL handler
414:                            handler.messageReceived(nextFilter, buf.buf());
415:
416:                            // Handle data to be forwarded to application or written to net
417:                            handleSslData(nextFilter, handler);
418:
419:                            if (handler.isInboundDone()) {
420:                                if (handler.isOutboundDone()) {
421:                                    handler.destroy();
422:                                } else {
423:                                    initiateClosure(nextFilter, session);
424:                                }
425:
426:                                if (buf.hasRemaining()) {
427:                                    // Forward the data received after closure.
428:                                    handler.scheduleMessageReceived(nextFilter,
429:                                            buf);
430:                                }
431:                            }
432:                        } catch (SSLException ssle) {
433:                            if (!handler.isHandshakeComplete()) {
434:                                SSLException newSsle = new SSLHandshakeException(
435:                                        "SSL handshake failed.");
436:                                newSsle.initCause(ssle);
437:                                ssle = newSsle;
438:                            }
439:
440:                            throw ssle;
441:                        }
442:                    }
443:                }
444:
445:                handler.flushScheduledEvents();
446:            }
447:
448:            @Override
449:            public void messageSent(NextFilter nextFilter, IoSession session,
450:                    WriteRequest writeRequest) {
451:                if (writeRequest instanceof  EncryptedWriteRequest) {
452:                    EncryptedWriteRequest wrappedRequest = (EncryptedWriteRequest) writeRequest;
453:                    nextFilter.messageSent(session, wrappedRequest
454:                            .getParentRequest());
455:                } else {
456:                    // ignore extra buffers used for handshaking
457:                }
458:            }
459:
460:            @Override
461:            public void exceptionCaught(NextFilter nextFilter,
462:                    IoSession session, Throwable cause) throws Exception {
463:
464:                if (cause instanceof  WriteToClosedSessionException) {
465:                    // Filter out SSL close notify, which is likely to fail to flush
466:                    // due to disconnection.
467:                    WriteToClosedSessionException e = (WriteToClosedSessionException) cause;
468:                    List<WriteRequest> failedRequests = e.getRequests();
469:                    boolean containsCloseNotify = false;
470:                    for (WriteRequest r : failedRequests) {
471:                        if (isCloseNotify(r.getMessage())) {
472:                            containsCloseNotify = true;
473:                            break;
474:                        }
475:                    }
476:
477:                    if (containsCloseNotify) {
478:                        if (failedRequests.size() == 1) {
479:                            // close notify is the only failed request; bail out.
480:                            return;
481:                        }
482:
483:                        List<WriteRequest> newFailedRequests = new ArrayList<WriteRequest>(
484:                                failedRequests.size() - 1);
485:                        for (WriteRequest r : failedRequests) {
486:                            if (!isCloseNotify(r.getMessage())) {
487:                                newFailedRequests.add(r);
488:                            }
489:                        }
490:
491:                        if (newFailedRequests.isEmpty()) {
492:                            // the failedRequests were full with close notify; bail out.
493:                            return;
494:                        }
495:
496:                        cause = new WriteToClosedSessionException(
497:                                newFailedRequests, cause.getMessage(), cause
498:                                        .getCause());
499:                    }
500:                }
501:
502:                nextFilter.exceptionCaught(session, cause);
503:            }
504:
505:            private boolean isCloseNotify(Object message) {
506:                if (!(message instanceof  IoBuffer)) {
507:                    return false;
508:                }
509:
510:                IoBuffer buf = (IoBuffer) message;
511:                int offset = buf.position();
512:                return buf.remaining() == 23 && buf.get(offset + 0) == 0x15
513:                        && buf.get(offset + 1) == 0x03
514:                        && buf.get(offset + 2) == 0x01
515:                        && buf.get(offset + 3) == 0x00
516:                        && buf.get(offset + 4) == 0x12;
517:            }
518:
519:            @Override
520:            public void filterWrite(NextFilter nextFilter, IoSession session,
521:                    WriteRequest writeRequest) throws SSLException {
522:                boolean needsFlush = true;
523:                SslHandler handler = getSslSessionHandler(session);
524:                synchronized (handler) {
525:                    if (!isSslStarted(session)) {
526:                        handler.scheduleFilterWrite(nextFilter, writeRequest);
527:                    }
528:                    // Don't encrypt the data if encryption is disabled.
529:                    else if (session.containsAttribute(DISABLE_ENCRYPTION_ONCE)) {
530:                        // Remove the marker attribute because it is temporary.
531:                        session.removeAttribute(DISABLE_ENCRYPTION_ONCE);
532:                        handler.scheduleFilterWrite(nextFilter, writeRequest);
533:                    } else {
534:                        // Otherwise, encrypt the buffer.
535:                        IoBuffer buf = (IoBuffer) writeRequest.getMessage();
536:
537:                        if (handler.isWritingEncryptedData()) {
538:                            // data already encrypted; simply return buffer
539:                            handler.scheduleFilterWrite(nextFilter,
540:                                    writeRequest);
541:                        } else if (handler.isHandshakeComplete()) {
542:                            // SSL encrypt
543:                            int pos = buf.position();
544:                            handler.encrypt(buf.buf());
545:                            buf.position(pos);
546:                            IoBuffer encryptedBuffer = handler
547:                                    .fetchOutNetBuffer();
548:                            handler.scheduleFilterWrite(nextFilter,
549:                                    new EncryptedWriteRequest(writeRequest,
550:                                            encryptedBuffer));
551:                        } else {
552:                            if (session.isConnected()) {
553:                                // Handshake not complete yet.
554:                                handler.schedulePreHandshakeWriteRequest(
555:                                        nextFilter, writeRequest);
556:                            }
557:                            needsFlush = false;
558:                        }
559:                    }
560:                }
561:
562:                if (needsFlush) {
563:                    handler.flushScheduledEvents();
564:                }
565:            }
566:
567:            @Override
568:            public void filterClose(final NextFilter nextFilter,
569:                    final IoSession session) throws SSLException {
570:                SslHandler handler = getSslSessionHandler0(session);
571:                if (handler == null) {
572:                    // The connection might already have closed, or
573:                    // SSL might have not started yet.
574:                    nextFilter.filterClose(session);
575:                    return;
576:                }
577:
578:                WriteFuture future = null;
579:                try {
580:                    synchronized (handler) {
581:                        if (isSslStarted(session)) {
582:                            future = initiateClosure(nextFilter, session);
583:                            future
584:                                    .addListener(new IoFutureListener<IoFuture>() {
585:                                        public void operationComplete(
586:                                                IoFuture future) {
587:                                            nextFilter.filterClose(session);
588:                                        }
589:                                    });
590:                        }
591:                    }
592:
593:                    handler.flushScheduledEvents();
594:                } finally {
595:                    if (future == null) {
596:                        nextFilter.filterClose(session);
597:                    }
598:                }
599:            }
600:
601:            private void initiateHandshake(NextFilter nextFilter,
602:                    IoSession session) throws SSLException {
603:                SslHandler handler = getSslSessionHandler(session);
604:                synchronized (handler) {
605:                    handler.handshake(nextFilter);
606:                }
607:                handler.flushScheduledEvents();
608:            }
609:
610:            private WriteFuture initiateClosure(NextFilter nextFilter,
611:                    IoSession session) throws SSLException {
612:                SslHandler handler = getSslSessionHandler(session);
613:                // if already shut down
614:                if (!handler.closeOutbound()) {
615:                    return DefaultWriteFuture.newNotWrittenFuture(session,
616:                            new IllegalStateException(
617:                                    "SSL session is shut down already."));
618:                }
619:
620:                // there might be data to write out here?
621:                WriteFuture future = handler.writeNetBuffer(nextFilter);
622:                if (future == null) {
623:                    future = DefaultWriteFuture.newWrittenFuture(session);
624:                }
625:
626:                if (handler.isInboundDone()) {
627:                    handler.destroy();
628:                }
629:
630:                if (session.containsAttribute(USE_NOTIFICATION)) {
631:                    handler.scheduleMessageReceived(nextFilter,
632:                            SESSION_UNSECURED);
633:                }
634:
635:                return future;
636:            }
637:
638:            // Utiliities
639:
640:            private void handleSslData(NextFilter nextFilter, SslHandler handler)
641:                    throws SSLException {
642:                // Flush any buffered write requests occurred before handshaking.
643:                if (handler.isHandshakeComplete()) {
644:                    handler.flushPreHandshakeEvents();
645:                }
646:
647:                // Write encrypted data to be written (if any)
648:                handler.writeNetBuffer(nextFilter);
649:
650:                // handle app. data read (if any)
651:                handleAppDataRead(nextFilter, handler);
652:            }
653:
654:            private void handleAppDataRead(NextFilter nextFilter,
655:                    SslHandler handler) {
656:                // forward read app data
657:                IoBuffer readBuffer = handler.fetchAppBuffer();
658:                if (readBuffer.hasRemaining()) {
659:                    handler.scheduleMessageReceived(nextFilter, readBuffer);
660:                }
661:            }
662:
663:            private SslHandler getSslSessionHandler(IoSession session) {
664:                SslHandler handler = getSslSessionHandler0(session);
665:                if (handler == null) {
666:                    throw new IllegalStateException();
667:                }
668:                if (handler.getParent() != this ) {
669:                    throw new IllegalArgumentException(
670:                            "Not managed by this filter.");
671:                }
672:                return handler;
673:            }
674:
675:            private SslHandler getSslSessionHandler0(IoSession session) {
676:                return (SslHandler) session.getAttribute(SSL_HANDLER);
677:            }
678:
679:            /**
680:             * A message that is sent from {@link SslFilter} when the connection became
681:             * secure or is not secure anymore.
682:             *
683:             * @author The Apache MINA Project (dev@mina.apache.org)
684:             * @version $Rev: 616100 $, $Date: 2008-01-28 15:58:32 -0700 (Mon, 28 Jan 2008) $
685:             */
686:            public static class SslFilterMessage {
687:                private final String name;
688:
689:                private SslFilterMessage(String name) {
690:                    this .name = name;
691:                }
692:
693:                @Override
694:                public String toString() {
695:                    return name;
696:                }
697:            }
698:
699:            private static class EncryptedWriteRequest extends
700:                    WriteRequestWrapper {
701:                private final IoBuffer encryptedMessage;
702:
703:                private EncryptedWriteRequest(WriteRequest writeRequest,
704:                        IoBuffer encryptedMessage) {
705:                    super (writeRequest);
706:                    this .encryptedMessage = encryptedMessage;
707:                }
708:
709:                @Override
710:                public Object getMessage() {
711:                    return encryptedMessage;
712:                }
713:            }
714:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.