src/main/java/org/java_websocket/SSLSocketChannel.java
private boolean doHandshake() throws IOException {
		SSLEngineResult result;
		HandshakeStatus handshakeStatus;

		// NioSslPeer's fields myAppData and peerAppData are supposed to be large enough to hold all message data the peer
		// will send and expects to receive from the other peer respectively. Since the messages to be exchanged will usually be less
		// than 16KB long the capacity of these fields should also be smaller. Here we initialize these two local buffers
		// to be used for the handshake, while keeping client's buffers at the same size.
		int appBufferSize = engine.getSession().getApplicationBufferSize();
		myAppData = ByteBuffer.allocate( appBufferSize );
		peerAppData = ByteBuffer.allocate( appBufferSize );
		myNetData.clear();
		peerNetData.clear();

		handshakeStatus = engine.getHandshakeStatus();
		boolean handshakeComplete = false;
		while( !handshakeComplete) {
			switch(handshakeStatus) {
				case FINISHED:
					handshakeComplete = !this.peerNetData.hasRemaining();
					if (handshakeComplete)
						return true;
					socketChannel.write(this.peerNetData);
					break;
				case NEED_UNWRAP:
					if( socketChannel.read( peerNetData ) < 0 ) {
						if( engine.isInboundDone() && engine.isOutboundDone() ) {
							return false;
						}
						try {
							engine.closeInbound();
						} catch ( SSLException e ) {
							//Ignore, cant do anything against this exception
						}
						engine.closeOutbound();
						// After closeOutbound the engine will be set to WRAP state, in order to try to send a close message to the client.
						handshakeStatus = engine.getHandshakeStatus();
						break;
					}
					peerNetData.flip();
					try {
						result = engine.unwrap( peerNetData, peerAppData );
						peerNetData.compact();
						handshakeStatus = result.getHandshakeStatus();
					} catch ( SSLException sslException ) {
						engine.closeOutbound();
						handshakeStatus = engine.getHandshakeStatus();
						break;
					}
					switch(result.getStatus()) {
						case OK:
							break;
						case BUFFER_OVERFLOW:
							// Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap.
							peerAppData = enlargeApplicationBuffer( peerAppData );
							break;
						case BUFFER_UNDERFLOW:
							// Will occur either when no data was read from the peer or when the peerNetData buffer was too small to hold all peer's data.
							peerNetData = handleBufferUnderflow( peerNetData );
							break;
						case CLOSED:
							if( engine.isOutboundDone() ) {
								return false;
							} else {
								engine.closeOutbound();
								handshakeStatus = engine.getHandshakeStatus();
								break;
							}
						default:
							throw new IllegalStateException( "Invalid SSL status: " + result.getStatus() );
					}
					break;
				case NEED_WRAP:
					myNetData.clear();
					try {
						result = engine.wrap( myAppData, myNetData );
						handshakeStatus = result.getHandshakeStatus();
					} catch ( SSLException sslException ) {
						engine.closeOutbound();
						handshakeStatus = engine.getHandshakeStatus();
						break;
					}
					switch(result.getStatus()) {
						case OK:
							myNetData.flip();
							while( myNetData.hasRemaining() ) {
								socketChannel.write( myNetData );
							}
							break;
						case BUFFER_OVERFLOW:
							// Will occur if there is not enough space in myNetData buffer to write all the data that would be generated by the method wrap.
							// Since myNetData is set to session's packet size we should not get to this point because SSLEngine is supposed
							// to produce messages smaller or equal to that, but a general handling would be the following:
							myNetData = enlargePacketBuffer( myNetData );
							break;
						case BUFFER_UNDERFLOW:
							throw new SSLException( "Buffer underflow occured after a wrap. I don't think we should ever get here." );
						case CLOSED:
							try {
								myNetData.flip();
								while( myNetData.hasRemaining() ) {
									socketChannel.write( myNetData );
								}
								// At this point the handshake status will probably be NEED_UNWRAP so we make sure that peerNetData is clear to read.
								peerNetData.clear();
							} catch ( Exception e ) {
								handshakeStatus = engine.getHandshakeStatus();
							}
							break;
						default:
							throw new IllegalStateException( "Invalid SSL status: " + result.getStatus() );
					}
					break;
				case NEED_TASK:
					Runnable task;
					while( ( task = engine.getDelegatedTask() ) != null ) {
						executor.execute( task );
					}
					handshakeStatus = engine.getHandshakeStatus();
					break;

				case NOT_HANDSHAKING:
					break;
				default:
					throw new IllegalStateException( "Invalid SSL status: " + handshakeStatus );
			}
		}

		return true;

	}
private boolean doHandshake() throws IOException {
		SSLEngineResult result;
		HandshakeStatus handshakeStatus;

		// NioSslPeer's fields myAppData and peerAppData are supposed to be large enough to hold all message data the peer
		// will send and expects to receive from the other peer respectively. Since the messages to be exchanged will usually be less
		// than 16KB long the capacity of these fields should also be smaller. Here we initialize these two local buffers
		// to be used for the handshake, while keeping client's buffers at the same size.
		int appBufferSize = engine.getSession().getApplicationBufferSize();
		myAppData = ByteBuffer.allocate( appBufferSize );
		peerAppData = ByteBuffer.allocate( appBufferSize );
		myNetData.clear();
		peerNetData.clear();

		handshakeStatus = engine.getHandshakeStatus();
		boolean handshakeComplete = false;
		while( !handshakeComplete) {
			switch(handshakeStatus) {
				case FINISHED:
					handshakeComplete = !this.peerNetData.hasRemaining();
					if (handshakeComplete)
						return true;
					socketChannel.write(this.peerNetData);
					break;
				case NEED_UNWRAP:
					if( socketChannel.read( peerNetData ) < 0 ) {
						if( engine.isInboundDone() && engine.isOutboundDone() ) {
							return false;
						}
						try {
							engine.closeInbound();
						} catch ( SSLException e ) {
							//Ignore, cant do anything against this exception
						}
						engine.closeOutbound();
						// After closeOutbound the engine will be set to WRAP state, in order to try to send a close message to the client.
						handshakeStatus = engine.getHandshakeStatus();
						break;
					}
					peerNetData.flip();
					try {
						result = engine.unwrap( peerNetData, peerAppData );
						peerNetData.compact();
						handshakeStatus = result.getHandshakeStatus();
					} catch ( SSLException sslException ) {
						engine.closeOutbound();
						handshakeStatus = engine.getHandshakeStatus();
						break;
					}
					switch(result.getStatus()) {
						case OK:
							break;
						case BUFFER_OVERFLOW:
							// Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap.
							peerAppData = enlargeApplicationBuffer( peerAppData );
							break;
						case BUFFER_UNDERFLOW:
							// Will occur either when no data was read from the peer or when the peerNetData buffer was too small to hold all peer's data.
							peerNetData = handleBufferUnderflow( peerNetData );
							break;
						case CLOSED:
							if( engine.isOutboundDone() ) {
								return false;
							} else {
								engine.closeOutbound();
								handshakeStatus = engine.getHandshakeStatus();
								break;
							}
						default:
							throw new IllegalStateException( "Invalid SSL status: " + result.getStatus() );
					}
					break;
				case NEED_WRAP:
					myNetData.clear();
					try {
						result = engine.wrap( myAppData, myNetData );
						handshakeStatus = result.getHandshakeStatus();
					} catch ( SSLException sslException ) {
						engine.closeOutbound();
						handshakeStatus = engine.getHandshakeStatus();
						break;
					}
					switch(result.getStatus()) {
						case OK:
							myNetData.flip();
							while( myNetData.hasRemaining() ) {
								socketChannel.write( myNetData );
							}
							break;
						case BUFFER_OVERFLOW:
							// Will occur if there is not enough space in myNetData buffer to write all the data that would be generated by the method wrap.
							// Since myNetData is set to session's packet size we should not get to this point because SSLEngine is supposed
							// to produce messages smaller or equal to that, but a general handling would be the following:
							myNetData = enlargePacketBuffer( myNetData );
							break;
						case BUFFER_UNDERFLOW:
							throw new SSLException( "Buffer underflow occured after a wrap. I don't think we should ever get here." );
						case CLOSED:
							try {
								myNetData.flip();
								while( myNetData.hasRemaining() ) {
									socketChannel.write( myNetData );
								}
								// At this point the handshake status will probably be NEED_UNWRAP so we make sure that peerNetData is clear to read.
								peerNetData.clear();
							} catch ( Exception e ) {
								handshakeStatus = engine.getHandshakeStatus();
							}
							break;
						default:
							throw new IllegalStateException( "Invalid SSL status: " + result.getStatus() );
					}
					break;
				case NEED_TASK:
					Runnable task;
					while( ( task = engine.getDelegatedTask() ) != null ) {
						executor.execute( task );
					}
					handshakeStatus = engine.getHandshakeStatus();
					break;

				case NOT_HANDSHAKING:
					break;
				default:
					throw new IllegalStateException( "Invalid SSL status: " + handshakeStatus );
			}
		}

		return true;

	}
private boolean doHandshake ( ) throws IOException { SSLEngineResult result ; HandshakeStatus handshakeStatus ; // NioSslPeer's fields myAppData and peerAppData are supposed to be large enough to hold all message data the peer // will send and expects to receive from the other peer respectively. Since the messages to be exchanged will usually be less // than 16KB long the capacity of these fields should also be smaller. Here we initialize these two local buffers // to be used for the handshake, while keeping client's buffers at the same size. int appBufferSize = engine . getSession ( ) . getApplicationBufferSize ( ) ; myAppData = ByteBuffer . allocate ( appBufferSize ) ; peerAppData = ByteBuffer . allocate ( appBufferSize ) ; myNetData . clear ( ) ; peerNetData . clear ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; boolean handshakeComplete = false ; while ( ! handshakeComplete ) { switch ( handshakeStatus ) { case FINISHED : handshakeComplete = ! this . peerNetData . hasRemaining ( ) ; if ( handshakeComplete ) return true ; socketChannel . write ( this . peerNetData ) ; break ; case NEED_UNWRAP : if ( socketChannel . read ( peerNetData ) < 0 ) { if ( engine . isInboundDone ( ) && engine . isOutboundDone ( ) ) { return false ; } try { engine . closeInbound ( ) ; } catch ( SSLException e ) { //Ignore, cant do anything against this exception } engine . closeOutbound ( ) ; // After closeOutbound the engine will be set to WRAP state, in order to try to send a close message to the client. handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } peerNetData . flip ( ) ; try { result = engine . unwrap ( peerNetData , peerAppData ) ; peerNetData . compact ( ) ; handshakeStatus = result . getHandshakeStatus ( ) ; } catch ( SSLException sslException ) { engine . closeOutbound ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } switch ( result . getStatus ( ) ) { case OK : break ; case BUFFER_OVERFLOW : // Will occur when peerAppData's capacity is smaller than the data derived from peerNetData's unwrap. peerAppData = enlargeApplicationBuffer ( peerAppData ) ; break ; case BUFFER_UNDERFLOW : // Will occur either when no data was read from the peer or when the peerNetData buffer was too small to hold all peer's data. peerNetData = handleBufferUnderflow ( peerNetData ) ; break ; case CLOSED : if ( engine . isOutboundDone ( ) ) { return false ; } else { engine . closeOutbound ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } default : throw new IllegalStateException ( "Invalid SSL status: " + result . getStatus ( ) ) ; } break ; case NEED_WRAP : myNetData . clear ( ) ; try { result = engine . wrap ( myAppData , myNetData ) ; handshakeStatus = result . getHandshakeStatus ( ) ; } catch ( SSLException sslException ) { engine . closeOutbound ( ) ; handshakeStatus = engine . getHandshakeStatus ( ) ; break ; } switch ( result . getStatus ( ) ) { case OK : myNetData . flip ( ) ; while ( myNetData . hasRemaining ( ) ) { socketChannel . write ( myNetData ) ; } break ; case BUFFER_OVERFLOW : // Will occur if there is not enough space in myNetData buffer to write all the data that would be generated by the method wrap. // Since myNetData is set to session's packet size we should not get to this point because SSLEngine is supposed // to produce messages smaller or equal to that, but a general handling would be the following: myNetData = enlargePacketBuffer ( myNetData ) ; break ; case BUFFER_UNDERFLOW : throw new SSLException ( "Buffer underflow occured after a wrap. I don't think we should ever get here." ) ; case CLOSED : try { myNetData . flip ( ) ; while ( myNetData . hasRemaining ( ) ) { socketChannel . write ( myNetData ) ; } // At this point the handshake status will probably be NEED_UNWRAP so we make sure that peerNetData is clear to read. peerNetData . clear ( ) ; } catch ( Exception e ) { handshakeStatus = engine . getHandshakeStatus ( ) ; } break ; default : throw new IllegalStateException ( "Invalid SSL status: " + result . getStatus ( ) ) ; } break ; case NEED_TASK : Runnable task ; while ( ( task = engine . getDelegatedTask ( ) ) != null ) { executor . execute ( task ) ; } handshakeStatus = engine . getHandshakeStatus ( ) ; break ; case NOT_HANDSHAKING : break ; default : throw new IllegalStateException ( "Invalid SSL status: " + handshakeStatus ) ; } } return true ; }
Implements the handshake protocol between two peers, required for the establishment of the SSL/TLS connection.
During the handshake, encryption configuration information - such as the list of available cipher suites - will be exchanged
and if the handshake is successful will lead to an established SSL/TLS session.
<p>
<p/>
A typical handshake will usually contain the following steps:
<p>
<ul>
<li>1. wrap:     ClientHello</li>
<li>2. unwrap:   ServerHello/Cert/ServerHelloDone</li>
<li>3. wrap:     ClientKeyExchange</li>
<li>4. wrap:     ChangeCipherSpec</li>
<li>5. wrap:     Finished</li>
<li>6. unwrap:   ChangeCipherSpec</li>
<li>7. unwrap:   Finished</li>
</ul>
<p/>
Handshake is also used during the end of the session, in order to properly close the connection between the two peers.
A proper connection close will typically include the one peer sending a CLOSE message to another, and then wait for
the other's CLOSE message to close the transport link. The other peer from his perspective would read a CLOSE message
from his peer and then enter the handshake procedure to send his own CLOSE message as well.

@return True if the connection handshake was successful or false if an error occurred.
@throws IOException - if an error occurs during read/write to the socket channel.
Implements the handshake protocol between two peers required for the establishment of the SSL / TLS connection . During the handshake encryption configuration information - such as the list of available cipher suites - will be exchanged and if the handshake is successful will lead to an established SSL / TLS session . <p > <p / > A typical handshake will usually contain the following steps : <p > <ul > <li > 1 . wrap : ClientHello< / li > <li > 2 . unwrap : ServerHello / Cert / ServerHelloDone< / li > <li > 3 . wrap : ClientKeyExchange< / li > <li > 4 . wrap : ChangeCipherSpec< / li > <li > 5 . wrap : Finished< / li > <li > 6 . unwrap : ChangeCipherSpec< / li > <li > 7 . unwrap : Finished< / li > < / ul > <p / > Handshake is also used during the end of the session in order to properly close the connection between the two peers . A proper connection close will typically include the one peer sending a CLOSE message to another and then wait for the other s CLOSE message to close the transport link . The other peer from his perspective would read a CLOSE message from his peer and then enter the handshake procedure to send his own CLOSE message as well .