001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /**
019: * @author Alexander Y. Kleymenov
020: * @version $Revision$
021: */package org.apache.harmony.xnet.provider.jsse;
022:
023: import org.apache.harmony.xnet.provider.jsse.AlertException;
024: import org.apache.harmony.xnet.provider.jsse.SSLSocketOutputStream;
025: import org.apache.harmony.xnet.provider.jsse.SSLStreamedInput;
026: import org.apache.harmony.xnet.provider.jsse.SSLSessionImpl;
027:
028: import java.io.IOException;
029: import java.io.InputStream;
030: import java.io.OutputStream;
031: import java.net.InetAddress;
032: import java.net.SocketAddress;
033: import java.net.SocketException;
034: import java.net.UnknownHostException;
035: import java.util.ArrayList;
036: import javax.net.ssl.HandshakeCompletedEvent;
037: import javax.net.ssl.HandshakeCompletedListener;
038: import javax.net.ssl.SSLEngineResult;
039: import javax.net.ssl.SSLException;
040: import javax.net.ssl.SSLSession;
041: import javax.net.ssl.SSLSocket;
042:
043: /**
044: * SSLSocket implementation.
045: * @see javax.net.ssl.SSLSocket class documentation for more information.
046: */
047: public class SSLSocketImpl extends SSLSocket {
048:
049: // indicates if handshake has been started
050: private boolean handshake_started = false;
051:
052: // record protocol to be used
053: protected SSLRecordProtocol recordProtocol;
054: // handshake protocol to be used
055: private HandshakeProtocol handshakeProtocol;
056: // alert protocol to be used
057: private AlertProtocol alertProtocol;
058: // application data input stream, this stream is presented by
059: // ssl socket as an input stream. Additionaly this object is a
060: // place where application data will be stored by record protocol
061: private SSLSocketInputStream appDataIS;
062: // outcoming application data stream
063: private SSLSocketOutputStream appDataOS;
064: // active session object
065: private SSLSessionImpl session;
066:
067: private boolean socket_was_closed = false;
068:
069: // the sslParameters object incapsulates all the info
070: // about supported and enabled cipher suites and protocols,
071: // as well as the information about client/server mode of
072: // ssl socket, whether it require/want client authentication or not,
073: // and controls whether new SSL sessions may be established by this
074: // socket or not.
075: protected SSLParameters sslParameters;
076: // super's streams to be wrapped:
077: protected InputStream input;
078: protected OutputStream output;
079: // handshake complete listeners
080: private ArrayList listeners;
081: // logger
082: private Logger.Stream logger = Logger.getStream("socket");
083:
084: // ----------------- Constructors and initializers --------------------
085:
086: /**
087: * Constructor
088: * @param sslParameters: SSLParameters
089: * @see javax.net.ssl.SSLSocket#SSLSocket() method documentation
090: * for more information.
091: */
092: protected SSLSocketImpl(SSLParameters sslParameters) {
093: super ();
094: this .sslParameters = sslParameters;
095: // init should be called after creation!
096: }
097:
098: /**
099: * Constructor
100: * @param host: String
101: * @param port: int
102: * @param sslParameters: SSLParameters
103: * @throws IOException
104: * @throws UnknownHostException
105: * @see javax.net.ssl.SSLSocket#SSLSocket(String,int)
106: * method documentation for more information.
107: */
108: protected SSLSocketImpl(String host, int port,
109: SSLParameters sslParameters) throws IOException,
110: UnknownHostException {
111: super (host, port);
112: this .sslParameters = sslParameters;
113: init();
114: }
115:
116: /**
117: * Constructor
118: * @param host: String
119: * @param port: int
120: * @param localHost: InetAddress
121: * @param localPort: int
122: * @param sslParameters: SSLParameters
123: * @throws IOException
124: * @throws UnknownHostException
125: * @see javax.net.ssl.SSLSocket#SSLSocket(String,int,InetAddress,int)
126: * method documentation for more information.
127: */
128: protected SSLSocketImpl(String host, int port,
129: InetAddress localHost, int localPort,
130: SSLParameters sslParameters) throws IOException,
131: UnknownHostException {
132: super (host, port, localHost, localPort);
133: this .sslParameters = sslParameters;
134: init();
135: }
136:
137: /**
138: * Constructor
139: * @param host: InetAddress
140: * @param port: int
141: * @param sslParameters: SSLParameters
142: * @return
143: * @throws IOException
144: * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int)
145: * method documentation for more information.
146: */
147: protected SSLSocketImpl(InetAddress host, int port,
148: SSLParameters sslParameters) throws IOException {
149: super (host, port);
150: this .sslParameters = sslParameters;
151: init();
152: }
153:
154: /**
155: * Constructor
156: * @param address: InetAddress
157: * @param port: int
158: * @param localAddress: InetAddress
159: * @param localPort: int
160: * @param sslParameters: SSLParameters
161: * @return
162: * @throws IOException
163: * @see javax.net.ssl.SSLSocket#SSLSocket(InetAddress,int,InetAddress,int)
164: * method documentation for more information.
165: */
166: protected SSLSocketImpl(InetAddress address, int port,
167: InetAddress localAddress, int localPort,
168: SSLParameters sslParameters) throws IOException {
169: super (address, port, localAddress, localPort);
170: this .sslParameters = sslParameters;
171: init();
172: }
173:
174: /**
175: * Initialize the SSL socket.
176: */
177: protected void init() throws IOException {
178: if (appDataIS != null) {
179: // already initialized
180: return;
181: }
182: initTransportLayer();
183: appDataIS = new SSLSocketInputStream(this );
184: appDataOS = new SSLSocketOutputStream(this );
185: }
186:
187: /**
188: * Initialize the transport data streams.
189: */
190: protected void initTransportLayer() throws IOException {
191: input = super .getInputStream();
192: output = super .getOutputStream();
193: }
194:
195: /**
196: * Closes the transport data streams.
197: */
198: protected void closeTransportLayer() throws IOException {
199: super .close();
200: if (input != null) {
201: input.close();
202: output.close();
203: }
204: }
205:
206: // --------------- SSLParameters based methods ---------------------
207:
208: /**
209: * This method works according to the specification of implemented class.
210: * @see javax.net.ssl.SSLSocket#getSupportedCipherSuites()
211: * method documentation for more information
212: */
213: public String[] getSupportedCipherSuites() {
214: return CipherSuite.getSupportedCipherSuiteNames();
215: }
216:
217: /**
218: * This method works according to the specification of implemented class.
219: * @see javax.net.ssl.SSLSocket#getEnabledCipherSuites()
220: * method documentation for more information
221: */
222: public String[] getEnabledCipherSuites() {
223: return sslParameters.getEnabledCipherSuites();
224: }
225:
226: /**
227: * This method works according to the specification of implemented class.
228: * @see javax.net.ssl.SSLSocket#setEnabledCipherSuites(String[])
229: * method documentation for more information
230: */
231: public void setEnabledCipherSuites(String[] suites) {
232: sslParameters.setEnabledCipherSuites(suites);
233: }
234:
235: /**
236: * This method works according to the specification of implemented class.
237: * @see javax.net.ssl.SSLSocket#getSupportedProtocols()
238: * method documentation for more information
239: */
240: public String[] getSupportedProtocols() {
241: return (String[]) ProtocolVersion.supportedProtocols.clone();
242: }
243:
244: /**
245: * This method works according to the specification of implemented class.
246: * @see javax.net.ssl.SSLSocket#getEnabledProtocols()
247: * method documentation for more information
248: */
249: public String[] getEnabledProtocols() {
250: return sslParameters.getEnabledProtocols();
251: }
252:
253: /**
254: * This method works according to the specification of implemented class.
255: * @see javax.net.ssl.SSLSocket#setEnabledProtocols(String[])
256: * method documentation for more information
257: */
258: public void setEnabledProtocols(String[] protocols) {
259: sslParameters.setEnabledProtocols(protocols);
260: }
261:
262: /**
263: * This method works according to the specification of implemented class.
264: * @see javax.net.ssl.SSLSocket#setUseClientMode(boolean)
265: * method documentation for more information
266: */
267: public void setUseClientMode(boolean mode) {
268: if (handshake_started) {
269: throw new IllegalArgumentException(
270: "Could not change the mode after the initial handshake has begun.");
271: }
272: sslParameters.setUseClientMode(mode);
273: }
274:
275: /**
276: * This method works according to the specification of implemented class.
277: * @see javax.net.ssl.SSLSocket#getUseClientMode()
278: * method documentation for more information
279: */
280: public boolean getUseClientMode() {
281: return sslParameters.getUseClientMode();
282: }
283:
284: /**
285: * This method works according to the specification of implemented class.
286: * @see javax.net.ssl.SSLSocket#setNeedClientAuth(boolean)
287: * method documentation for more information
288: */
289: public void setNeedClientAuth(boolean need) {
290: sslParameters.setNeedClientAuth(need);
291: }
292:
293: /**
294: * This method works according to the specification of implemented class.
295: * @see javax.net.ssl.SSLSocket#getNeedClientAuth()
296: * method documentation for more information
297: */
298: public boolean getNeedClientAuth() {
299: return sslParameters.getNeedClientAuth();
300: }
301:
302: /**
303: * This method works according to the specification of implemented class.
304: * @see javax.net.ssl.SSLSocket#setWantClientAuth(boolean)
305: * method documentation for more information
306: */
307: public void setWantClientAuth(boolean want) {
308: sslParameters.setWantClientAuth(want);
309: }
310:
311: /**
312: * This method works according to the specification of implemented class.
313: * @see javax.net.ssl.SSLSocket#getWantClientAuth()
314: * method documentation for more information
315: */
316: public boolean getWantClientAuth() {
317: return sslParameters.getWantClientAuth();
318: }
319:
320: /**
321: * This method works according to the specification of implemented class.
322: * @see javax.net.ssl.SSLSocket#setEnableSessionCreation(boolean)
323: * method documentation for more information
324: */
325: public void setEnableSessionCreation(boolean flag) {
326: sslParameters.setEnableSessionCreation(flag);
327: }
328:
329: /**
330: * This method works according to the specification of implemented class.
331: * @see javax.net.ssl.SSLSocket#getEnableSessionCreation()
332: * method documentation for more information
333: */
334: public boolean getEnableSessionCreation() {
335: return sslParameters.getEnableSessionCreation();
336: }
337:
338: // -----------------------------------------------------------------
339:
340: /**
341: * This method works according to the specification of implemented class.
342: * @see javax.net.ssl.SSLSocket#getSession()
343: * method documentation for more information
344: */
345: public SSLSession getSession() {
346: if (!handshake_started) {
347: try {
348: startHandshake();
349: } catch (IOException e) {
350: // return an invalid session with
351: // invalid cipher suite of "SSL_NULL_WITH_NULL_NULL"
352: return SSLSessionImpl.NULL_SESSION;
353: }
354: }
355: return session;
356: }
357:
358: /**
359: * This method works according to the specification of implemented class.
360: * @see javax.net.ssl.SSLSocket#addHandshakeCompletedListener(HandshakeCompletedListener)
361: * method documentation for more information
362: */
363: public void addHandshakeCompletedListener(
364: HandshakeCompletedListener listener) {
365: if (listener == null) {
366: throw new IllegalArgumentException(
367: "Provided listener is null");
368: }
369: if (listeners == null) {
370: listeners = new ArrayList();
371: }
372: listeners.add(listener);
373: }
374:
375: /**
376: * This method works according to the specification of implemented class.
377: * @see javax.net.ssl.SSLSocket#removeHandshakeCompletedListener(HandshakeCompletedListener)
378: * method documentation for more information
379: */
380: public void removeHandshakeCompletedListener(
381: HandshakeCompletedListener listener) {
382: if (listener == null) {
383: throw new IllegalArgumentException(
384: "Provided listener is null");
385: }
386: if (listeners == null) {
387: throw new IllegalArgumentException(
388: "Provided listener is not registered");
389: }
390: if (!listeners.remove(listener)) {
391: throw new IllegalArgumentException(
392: "Provided listener is not registered");
393: }
394: }
395:
396: /**
397: * Performs the handshake process over the SSL/TLS connection
398: * as described in rfc 2246, TLS v1 specification
399: * http://www.ietf.org/rfc/rfc2246.txt. If the initial handshake
400: * has been already done, this method initiates rehandshake.
401: * This method works according to the specification of implemented class.
402: * @see javax.net.ssl.SSLSocket#startHandshake()
403: * method documentation for more information
404: */
405: public void startHandshake() throws IOException {
406: if (appDataIS == null) {
407: throw new IOException("Socket is not connected.");
408: }
409: if (socket_was_closed) {
410: throw new IOException("Socket has already been closed.");
411: }
412:
413: if (!handshake_started) {
414: handshake_started = true;
415: if (sslParameters.getUseClientMode()) {
416: if (logger != null) {
417: logger.println("SSLSocketImpl: CLIENT");
418: }
419: handshakeProtocol = new ClientHandshakeImpl(this );
420: } else {
421: if (logger != null) {
422: logger.println("SSLSocketImpl: SERVER");
423: }
424: handshakeProtocol = new ServerHandshakeImpl(this );
425: }
426:
427: alertProtocol = new AlertProtocol();
428: recordProtocol = new SSLRecordProtocol(handshakeProtocol,
429: alertProtocol, new SSLStreamedInput(input),
430: appDataIS.dataPoint);
431: }
432:
433: if (logger != null) {
434: logger.println("SSLSocketImpl.startHandshake");
435: }
436:
437: handshakeProtocol.start();
438:
439: doHandshake();
440:
441: if (logger != null) {
442: logger.println("SSLSocketImpl.startHandshake: END");
443: }
444: }
445:
446: // ---------------- Socket's methods overridings -------------------
447:
448: /**
449: * This method works according to the specification of implemented class.
450: * @see javax.net.ssl.SSLSocket#getInputStream()
451: * method documentation for more information
452: */
453: public InputStream getInputStream() throws IOException {
454: if (socket_was_closed) {
455: throw new IOException("Socket has already been closed.");
456: }
457: return appDataIS;
458: }
459:
460: /**
461: * This method works according to the specification of implemented class.
462: * @see javax.net.ssl.SSLSocket#getOutputStream()
463: * method documentation for more information
464: */
465: public OutputStream getOutputStream() throws IOException {
466: if (socket_was_closed) {
467: throw new IOException("Socket has already been closed.");
468: }
469: return appDataOS;
470: }
471:
472: /**
473: * This method works according to the specification of implemented class.
474: * @see java.net.Socket#connect(SocketAddress)
475: * method documentation for more information
476: */
477: public void connect(SocketAddress endpoint) throws IOException {
478: super .connect(endpoint);
479: init();
480: }
481:
482: /**
483: * This method works according to the specification of implemented class.
484: * @see java.net.Socket#connect(SocketAddress,int)
485: * method documentation for more information
486: */
487: public void connect(SocketAddress endpoint, int timeout)
488: throws IOException {
489: super .connect(endpoint, timeout);
490: init();
491: }
492:
493: /**
494: * This method works according to the specification of implemented class.
495: * @see javax.net.ssl.SSLSocket#close()
496: * method documentation for more information
497: */
498: public void close() throws IOException {
499: if (logger != null) {
500: logger.println("SSLSocket.close " + socket_was_closed);
501: }
502: if (!socket_was_closed) {
503: if (handshake_started) {
504: alertProtocol.alert(AlertProtocol.WARNING,
505: AlertProtocol.CLOSE_NOTIFY);
506: try {
507: output.write(alertProtocol.wrap());
508: } catch (IOException ex) {
509: }
510: alertProtocol.setProcessed();
511: }
512: shutdown();
513: closeTransportLayer();
514: socket_was_closed = true;
515: }
516: }
517:
518: /**
519: * This method is not supported for SSLSocket implementation.
520: */
521: public void sendUrgentData(int data) throws IOException {
522: throw new SocketException(
523: "Method sendUrgentData() is not supported.");
524: }
525:
526: /**
527: * This method is not supported for SSLSocket implementation.
528: */
529: public void setOOBInline(boolean on) throws SocketException {
530: throw new SocketException(
531: "Methods sendUrgentData, setOOBInline are not supported.");
532: }
533:
534: /**
535: * This method is not supported for SSLSocket implementation.
536: */
537: public void shutdownOutput() {
538: throw new UnsupportedOperationException(
539: "Method shutdownOutput() is not supported.");
540: }
541:
542: /**
543: * This method is not supported for SSLSocket implementation.
544: */
545: public void shutdownInput() {
546: throw new UnsupportedOperationException(
547: "Method shutdownInput() is not supported.");
548: }
549:
550: /**
551: * Returns the string representation of the object.
552: */
553: public String toString() {
554: return "[SSLSocketImpl]";
555: }
556:
557: // -----------------------------------------------------------------
558:
559: // Shutdownes the ssl socket and makes all cleanup work.
560: private void shutdown() {
561: if (handshake_started) {
562: alertProtocol.shutdown();
563: alertProtocol = null;
564: handshakeProtocol.shutdown();
565: handshakeProtocol = null;
566: recordProtocol.shutdown();
567: recordProtocol = null;
568: }
569: socket_was_closed = true;
570: }
571:
572: /**
573: * This method is called by SSLSocketInputStream class
574: * when client application tryes to read application data from
575: * the stream, but there is no data in its underlying buffer.
576: * @throws IOException
577: */
578: protected void needAppData() throws IOException {
579: if (!handshake_started) {
580: startHandshake();
581: }
582: int type;
583: if (logger != null) {
584: logger.println("SSLSocket.needAppData..");
585: }
586: try {
587: while (appDataIS.available() == 0) {
588: // read and unwrap the record contained in the transport
589: // input stream (SSLStreamedInput), pass it
590: // to appropriate client protocol (alert, handshake, or app)
591: // and retrieve the type of unwrapped data
592: switch (type = recordProtocol.unwrap()) {
593: case ContentType.HANDSHAKE:
594: if (!handshakeProtocol
595: .getStatus()
596: .equals(
597: SSLEngineResult.HandshakeStatus.NOT_HANDSHAKING)) {
598: // handshake protocol got addressed to it message
599: // and did not ignore it, so it's a rehandshake
600: doHandshake();
601: }
602: break;
603: case ContentType.ALERT:
604: processAlert();
605: if (socket_was_closed) {
606: return;
607: }
608: break;
609: case ContentType.APPLICATION_DATA:
610: if (logger != null) {
611: logger
612: .println("SSLSocket.needAppData: got the data");
613: }
614: break;
615: default:
616: // will throw exception
617: reportFatalAlert(AlertProtocol.UNEXPECTED_MESSAGE,
618: new SSLException(
619: "Unexpected message of type "
620: + type + " has been got"));
621: }
622: if (alertProtocol.hasAlert()) {
623: // warning alert occured during wrap or unwrap
624: // (note: fatal alert causes AlertException
625: // to be thrown)
626: output.write(alertProtocol.wrap());
627: alertProtocol.setProcessed();
628: }
629: if (socket_was_closed) {
630: appDataIS.setEnd();
631: return;
632: }
633: }
634: } catch (AlertException e) {
635: // will throw exception
636: reportFatalAlert(e.getDescriptionCode(), e.getReason());
637: } catch (EndOfSourceException e) {
638: // end of socket's input stream has been reached
639: appDataIS.setEnd();
640: }
641: if (logger != null) {
642: logger.println("SSLSocket.needAppData: app data len: "
643: + appDataIS.available());
644: }
645: }
646:
647: /**
648: * This method is called by SSLSocketOutputStream when client application
649: * tryes to send the data over ssl protocol.
650: */
651: protected void writeAppData(byte[] data, int offset, int len)
652: throws IOException {
653: if (!handshake_started) {
654: startHandshake();
655: }
656: if (logger != null) {
657: logger.println("SSLSocket.writeAppData: " + len + " "
658: + SSLRecordProtocol.MAX_DATA_LENGTH);
659: //logger.println(new String(data, offset, len));
660: }
661: try {
662: if (len < SSLRecordProtocol.MAX_DATA_LENGTH) {
663: output.write(recordProtocol
664: .wrap(ContentType.APPLICATION_DATA, data,
665: offset, len));
666: } else {
667: while (len >= SSLRecordProtocol.MAX_DATA_LENGTH) {
668: output.write(recordProtocol.wrap(
669: ContentType.APPLICATION_DATA, data, offset,
670: SSLRecordProtocol.MAX_DATA_LENGTH));
671: offset += SSLRecordProtocol.MAX_DATA_LENGTH;
672: len -= SSLRecordProtocol.MAX_DATA_LENGTH;
673: }
674: if (len > 0) {
675: output.write(recordProtocol.wrap(
676: ContentType.APPLICATION_DATA, data, offset,
677: len));
678: }
679: }
680: } catch (AlertException e) {
681: // will throw exception
682: reportFatalAlert(e.getDescriptionCode(), e.getReason());
683: }
684: }
685:
686: /*
687: * Performs handshake proccess over this connection. The hanshake
688: * process is dirrected by the handshake status code provided by
689: * handshake protocol. If this status is NEED_WRAP, method retrieves
690: * handshake message from handshake protocol and sends it to another peer.
691: * If this status is NEED_UNWRAP, method receives and processes handshake
692: * message from another peer. Each of this stages (wrap/unwrap) change
693: * the state of handshake protocol and this process is performed
694: * until handshake status is FINISHED. After handshake process is finnished
695: * handshake completed event are sent to the registered listeners.
696: * For more information about the handshake process see
697: * TLS v1 specification (http://www.ietf.org/rfc/rfc2246.txt) p 7.3.
698: */
699: private void doHandshake() throws IOException {
700: SSLEngineResult.HandshakeStatus status;
701: int type;
702: try {
703: while (!(status = handshakeProtocol.getStatus())
704: .equals(SSLEngineResult.HandshakeStatus.FINISHED)) {
705: if (logger != null) {
706: String s = (status
707: .equals(SSLEngineResult.HandshakeStatus.NEED_WRAP)) ? "NEED_WRAP"
708: : (status
709: .equals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) ? "NEED_UNWRAP"
710: : "STATUS: OTHER!";
711: logger.println("SSLSocketImpl: HS status: " + s
712: + " " + status);
713: }
714: if (status
715: .equals(SSLEngineResult.HandshakeStatus.NEED_WRAP)) {
716: output.write(handshakeProtocol.wrap());
717: } else if (status
718: .equals(SSLEngineResult.HandshakeStatus.NEED_UNWRAP)) {
719: // read and unwrap the record contained in the transport
720: // input stream (SSLStreamedInput), pass it
721: // to appropriate client protocol (alert, handshake, or app)
722: // and retrieve the type of unwrapped data
723: switch (type = recordProtocol.unwrap()) {
724: case ContentType.HANDSHAKE:
725: case ContentType.CHANGE_CIPHER_SPEC:
726: break;
727: case ContentType.APPLICATION_DATA:
728: // So it's rehandshake and
729: // if app data buffer will be overloaded
730: // it will throw alert exception.
731: // Probably we should count the number of
732: // not handshaking data and make additional
733: // constraints (do not expect buffer overflow).
734: break;
735: case ContentType.ALERT:
736: processAlert();
737: if (socket_was_closed) {
738: return;
739: }
740: break;
741: default:
742: // will throw exception
743: reportFatalAlert(
744: AlertProtocol.UNEXPECTED_MESSAGE,
745: new SSLException(
746: "Unexpected message of type "
747: + type
748: + " has been got"));
749: }
750: } else {
751: // will throw exception
752: reportFatalAlert(AlertProtocol.INTERNAL_ERROR,
753: new SSLException(
754: "Handshake passed unexpected status: "
755: + status));
756: }
757: if (alertProtocol.hasAlert()) {
758: // warning alert uccured during wrap or unwrap
759: // (note: fatal alert causes AlertException
760: // to be thrown)
761: output.write(alertProtocol.wrap());
762: alertProtocol.setProcessed();
763: }
764: }
765: } catch (EndOfSourceException e) {
766: appDataIS.setEnd();
767: throw new IOException("Connection was closed");
768: } catch (AlertException e) {
769: // will throw exception
770: reportFatalAlert(e.getDescriptionCode(), e.getReason());
771: }
772:
773: session = recordProtocol.getSession();
774: if (listeners != null) {
775: // notify the listeners
776: HandshakeCompletedEvent event = new HandshakeCompletedEvent(
777: this , session);
778: int size = listeners.size();
779: for (int i = 0; i < size; i++) {
780: ((HandshakeCompletedListener) listeners.get(i))
781: .handshakeCompleted(event);
782: }
783: }
784: }
785:
786: /*
787: * Process received alert message
788: */
789: private void processAlert() throws IOException {
790: if (!alertProtocol.hasAlert()) {
791: return;
792: }
793: if (alertProtocol.isFatalAlert()) {
794: alertProtocol.setProcessed();
795: String description = "Fatal alert received "
796: + alertProtocol.getAlertDescription();
797: shutdown();
798: throw new SSLException(description);
799: } else {
800: if (logger != null) {
801: logger.println("Warning alert received: "
802: + alertProtocol.getAlertDescription());
803: }
804: switch (alertProtocol.getDescriptionCode()) {
805: case AlertProtocol.CLOSE_NOTIFY:
806: alertProtocol.setProcessed();
807: appDataIS.setEnd();
808: close();
809: return;
810: default:
811: alertProtocol.setProcessed();
812: // TODO: process other warning messages
813: }
814: }
815: }
816:
817: /*
818: * Sends fatal alert message and throws exception
819: */
820: private void reportFatalAlert(byte description_code,
821: SSLException reason) throws IOException {
822: alertProtocol.alert(AlertProtocol.FATAL, description_code);
823: try {
824: // the output stream can be closed
825: output.write(alertProtocol.wrap());
826: } catch (IOException ex) {
827: }
828: alertProtocol.setProcessed();
829: shutdown();
830: throw reason;
831: }
832: }
|