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