1+ /**
2+ * Copyright (C) 2003 Alexander Kout
3+ * Originally from the jFxp project (http://jfxp.sourceforge.net/).
4+ * Copied with permission June 11, 2012 by Femi Omojola (fomojola@ideasynthesis.com).
5+ */
6+ package org .java_websocket ;
7+
8+ import java .io .IOException ;
9+ import java .net .Socket ;
10+ import java .net .SocketAddress ;
11+ import java .nio .ByteBuffer ;
12+ import java .nio .channels .ByteChannel ;
13+ import java .nio .channels .SelectableChannel ;
14+ import java .nio .channels .SelectionKey ;
15+ import java .nio .channels .SocketChannel ;
16+
17+ import javax .net .ssl .SSLEngine ;
18+ import javax .net .ssl .SSLEngineResult ;
19+ import javax .net .ssl .SSLException ;
20+ import javax .net .ssl .SSLSession ;
21+
22+ /**
23+ * Implements the relevant portions of the SocketChannel interface with the SSLEngine wrapper.
24+ */
25+ public class SSLSocketChannel2 implements ByteChannel {
26+ /** raw payload incomming */
27+ private ByteBuffer clientIn ;
28+ /** raw payload outgoing */
29+ private ByteBuffer clientOut ;
30+ /** encrypted data outgoing */
31+ private ByteBuffer cTOs ;
32+ /** encrypted data incoming */
33+ private ByteBuffer sTOc ;
34+
35+ private SocketChannel sc ;
36+ private SelectionKey key ;
37+
38+ private SSLEngineResult res ;
39+ private SSLEngine sslEngine ;
40+ private int SSL ;
41+
42+ public SSLSocketChannel2 ( SelectionKey key , SSLEngine sslEngine ) throws IOException {
43+ this .sc = (SocketChannel ) key .channel ();
44+ this .key = key ;
45+ this .sslEngine = sslEngine ;
46+ SSL = 1 ;
47+ try {
48+ sslEngine .setEnableSessionCreation ( true );
49+ SSLSession session = sslEngine .getSession ();
50+ createBuffers ( session );
51+ // wrap
52+ clientOut .clear ();
53+ sc .write ( wrap ( clientOut ) );
54+ assert ( !clientOut .hasRemaining () );
55+ while ( res .getHandshakeStatus () != SSLEngineResult .HandshakeStatus .FINISHED ) {
56+ processHandshake ();
57+ }
58+ clientIn .clear ();
59+ clientIn .flip ();
60+ SSL = 4 ;
61+ } catch ( Exception e ) {
62+ e .printStackTrace ( System .out );
63+ SSL = 0 ;
64+ }
65+ }
66+
67+ private void processHandshake () throws IOException {
68+ assert ( res .getHandshakeStatus () != SSLEngineResult .HandshakeStatus .FINISHED );
69+ if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .NEED_UNWRAP ) {
70+ // unwrap
71+ if ( !sTOc .hasRemaining () )
72+ sTOc .clear ();
73+ sc .read ( sTOc );
74+ sTOc .flip ();
75+ unwrap ( sTOc );
76+ if ( res .getHandshakeStatus () != SSLEngineResult .HandshakeStatus .FINISHED ) {
77+ clientOut .clear ();
78+ sc .write ( wrap ( clientOut ) );
79+ }
80+ } else if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .NEED_WRAP ) {
81+ // wrap
82+ clientOut .clear ();
83+ sc .write ( wrap ( clientOut ) );
84+ } else {
85+ assert ( false );
86+ }
87+
88+ }
89+
90+ private synchronized ByteBuffer wrap ( ByteBuffer b ) throws SSLException {
91+ cTOs .clear ();
92+ res = sslEngine .wrap ( b , cTOs );
93+ cTOs .flip ();
94+ return cTOs ;
95+ }
96+
97+ private synchronized ByteBuffer unwrap ( ByteBuffer b ) throws SSLException {
98+ clientIn .clear ();
99+ while ( b .hasRemaining () ) {
100+ res = sslEngine .unwrap ( b , clientIn );
101+ if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .NEED_TASK ) {
102+ // Task
103+ Runnable task ;
104+ while ( ( task = sslEngine .getDelegatedTask () ) != null ) {
105+ task .run ();
106+ }
107+ } else if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .FINISHED ) {
108+ return clientIn ;
109+ } else if ( res .getStatus () == SSLEngineResult .Status .BUFFER_UNDERFLOW ) {
110+ return clientIn ;
111+ }
112+ }
113+ return clientIn ;
114+ }
115+
116+ private void createBuffers ( SSLSession session ) {
117+ int appBufferMax = session .getApplicationBufferSize ();
118+ int netBufferMax = session .getPacketBufferSize ();
119+
120+ clientIn = ByteBuffer .allocate ( 65536 );
121+ clientOut = ByteBuffer .allocate ( appBufferMax );
122+
123+ cTOs = ByteBuffer .allocate ( netBufferMax );
124+ sTOc = ByteBuffer .allocate ( netBufferMax );
125+ }
126+
127+ public int write ( ByteBuffer src ) throws IOException {
128+ if ( SSL == 4 ) {
129+ return sc .write ( wrap ( src ) );
130+ }
131+ return sc .write ( src );
132+ }
133+
134+ public int read ( ByteBuffer dst ) throws IOException {
135+ int amount = 0 , limit ;
136+ if ( SSL == 4 ) {
137+ // test if there was a buffer overflow in dst
138+ if ( clientIn .hasRemaining () ) {
139+ limit = Math .min ( clientIn .remaining (), dst .remaining () );
140+ for ( int i = 0 ; i < limit ; i ++ ) {
141+ dst .put ( clientIn .get () );
142+ amount ++;
143+ }
144+ return amount ;
145+ }
146+ // test if some bytes left from last read (e.g. BUFFER_UNDERFLOW)
147+ if ( sTOc .hasRemaining () ) {
148+ unwrap ( sTOc );
149+ clientIn .flip ();
150+ limit = Math .min ( clientIn .limit (), dst .remaining () );
151+ for ( int i = 0 ; i < limit ; i ++ ) {
152+ dst .put ( clientIn .get () );
153+ amount ++;
154+ }
155+ if ( res .getStatus () != SSLEngineResult .Status .BUFFER_UNDERFLOW ) {
156+ sTOc .clear ();
157+ sTOc .flip ();
158+ return amount ;
159+ }
160+ }
161+ if ( !sTOc .hasRemaining () )
162+ sTOc .clear ();
163+ else
164+ sTOc .compact ();
165+
166+ if ( sc .read ( sTOc ) == -1 ) {
167+ sTOc .clear ();
168+ sTOc .flip ();
169+ return -1 ;
170+ }
171+ sTOc .flip ();
172+ unwrap ( sTOc );
173+ // write in dst
174+ clientIn .flip ();
175+ limit = Math .min ( clientIn .limit (), dst .remaining () );
176+ for ( int i = 0 ; i < limit ; i ++ ) {
177+ dst .put ( clientIn .get () );
178+ amount ++;
179+ }
180+ return amount ;
181+ }
182+ return sc .read ( dst );
183+ }
184+
185+ public boolean isConnected () {
186+ return sc .isConnected ();
187+ }
188+
189+ public void close () throws IOException {
190+ if ( SSL == 4 ) {
191+ sslEngine .closeOutbound ();
192+ sslEngine .getSession ().invalidate ();
193+ clientOut .clear ();
194+ sc .write ( wrap ( clientOut ) );
195+ sc .close ();
196+ } else
197+ sc .close ();
198+ }
199+
200+ public SelectableChannel configureBlocking ( boolean b ) throws IOException {
201+ return sc .configureBlocking ( b );
202+ }
203+
204+ public boolean connect ( SocketAddress remote ) throws IOException {
205+ return sc .connect ( remote );
206+ }
207+
208+ public boolean finishConnect () throws IOException {
209+ return sc .finishConnect ();
210+ }
211+
212+ public Socket socket () {
213+ return sc .socket ();
214+ }
215+
216+ public boolean isInboundDone () {
217+ return sslEngine .isInboundDone ();
218+ }
219+
220+ @ Override
221+ public boolean isOpen () {
222+ return sc .isOpen ();
223+ }
224+ }
0 commit comments