1313import java .nio .channels .SelectableChannel ;
1414import java .nio .channels .SelectionKey ;
1515import java .nio .channels .SocketChannel ;
16+ import java .util .ArrayList ;
17+ import java .util .Iterator ;
18+ import java .util .List ;
1619import java .util .concurrent .ExecutorService ;
20+ import java .util .concurrent .Future ;
1721
1822import javax .net .ssl .SSLEngine ;
1923import javax .net .ssl .SSLEngineResult ;
2024import javax .net .ssl .SSLEngineResult .HandshakeStatus ;
25+ import javax .net .ssl .SSLEngineResult .Status ;
2126import javax .net .ssl .SSLException ;
2227import javax .net .ssl .SSLSession ;
2328
2429/**
2530 * Implements the relevant portions of the SocketChannel interface with the SSLEngine wrapper.
2631 */
2732public class SSLSocketChannel2 implements ByteChannel , WrappedByteChannel {
28- private static ByteBuffer emptybuffer = ByteBuffer .allocate ( 0 );
33+ protected static ByteBuffer emptybuffer = ByteBuffer .allocate ( 0 );
2934
30- private ExecutorService exec ;
35+ protected ExecutorService exec ;
36+
37+ protected List <Future <?>> tasks ;
3138
3239 /** raw payload incomming */
33- private ByteBuffer inData ;
40+ protected ByteBuffer inData ;
3441 /** encrypted data outgoing */
35- private ByteBuffer outCrypt ;
42+ protected ByteBuffer outCrypt ;
3643 /** encrypted data incoming */
37- private ByteBuffer inCrypt ;
44+ protected ByteBuffer inCrypt ;
3845
39- private SocketChannel sc ;
40- private SelectionKey key ;
46+ protected SocketChannel sc ;
47+ protected SelectionKey key ;
4148
42- private SSLEngineResult res ;
43- private SSLEngine sslEngine ;
49+ protected SSLEngineResult res ;
50+ protected SSLEngine sslEngine ;
4451
4552 public SSLSocketChannel2 ( SelectionKey key , SSLEngine sslEngine , ExecutorService exec ) throws IOException {
4653 this .sc = (SocketChannel ) key .channel ();
4754 this .key = key ;
4855 this .sslEngine = sslEngine ;
4956 this .exec = exec ;
5057
58+ tasks = new ArrayList <Future <?>>( 3 );
59+
5160 this .key .interestOps ( key .interestOps () | SelectionKey .OP_WRITE );
5261
5362 sslEngine .setEnableSessionCreation ( true );
5463 SSLSession session = sslEngine .getSession ();
5564 createBuffers ( session );
5665
57- // there is not yet any user data
58- inData .flip ();
59- inCrypt .flip ();
60- outCrypt .flip ();
61-
62- sc .write ( wrap ( emptybuffer ) );
63-
66+ sc .write ( wrap ( emptybuffer ) );// initializes res
6467 processHandshake ();
6568 }
6669
67- private boolean processHandshake () throws IOException {
70+ private void processHandshake () throws IOException {
71+ if ( !tasks .isEmpty () ) {
72+ Iterator <Future <?>> it = tasks .iterator ();
73+ while ( it .hasNext () ) {
74+ Future <?> f = it .next ();
75+ if ( f .isDone () ) {
76+ it .remove ();
77+ } else {
78+ return ;
79+ }
80+ }
81+ }
82+
6883 if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .NEED_UNWRAP ) {
6984 inCrypt .compact ();
7085 sc .read ( inCrypt );
7186 inCrypt .flip ();
87+ inData .compact ();
7288 unwrap ();
73- if ( res .getHandshakeStatus () != SSLEngineResult .HandshakeStatus .FINISHED ) {
74- sc .write ( wrap ( emptybuffer ) );
75- }
76- } else if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .NEED_WRAP ) {
89+ }
90+ consumeDelegatedTasks ();
91+ if ( tasks .isEmpty () || res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .NEED_WRAP ) {
7792 sc .write ( wrap ( emptybuffer ) );
78- } else {
79- assert ( false );
8093 }
8194
82- return false ;
8395 }
8496
8597 private synchronized ByteBuffer wrap ( ByteBuffer b ) throws SSLException {
@@ -90,59 +102,59 @@ private synchronized ByteBuffer wrap( ByteBuffer b ) throws SSLException {
90102 }
91103
92104 private synchronized ByteBuffer unwrap () throws SSLException {
93- inData .compact ();
94- while ( inCrypt .hasRemaining () ) {
105+ int rem ;
106+ do {
107+ rem = inData .remaining ();
95108 res = sslEngine .unwrap ( inCrypt , inData );
96- if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .NEED_TASK ) {
97- Runnable task ;
98- while ( ( task = sslEngine .getDelegatedTask () ) != null ) {
99- task .run ();
100- }
101- } else if ( res .getHandshakeStatus () == SSLEngineResult .HandshakeStatus .FINISHED ) {
102- break ;
103- } else if ( res .getStatus () == SSLEngineResult .Status .BUFFER_UNDERFLOW ) {
104- break ;
105- } else if ( res .getStatus () == SSLEngineResult .Status .BUFFER_OVERFLOW ) {
106- throw new RuntimeException ( "destenation buffer to small" );
107- }
108- }
109+ } while ( rem != inData .remaining () );
110+
109111 inData .flip ();
110112 return inData ;
111113 }
112114
115+ protected void consumeDelegatedTasks () {
116+ Runnable task ;
117+ while ( ( task = sslEngine .getDelegatedTask () ) != null ) {
118+ tasks .add ( exec .submit ( task ) );
119+ // task.run();
120+ }
121+ }
122+
113123 protected void createBuffers ( SSLSession session ) {
114124 int appBufferMax = session .getApplicationBufferSize ();
115125 int netBufferMax = session .getPacketBufferSize ();
116126
117127 inData = ByteBuffer .allocate ( appBufferMax );
118128 outCrypt = ByteBuffer .allocate ( netBufferMax );
119129 inCrypt = ByteBuffer .allocate ( netBufferMax );
130+ inData .flip ();
131+ inCrypt .flip ();
132+ outCrypt .flip ();
120133 }
121134
122135 public int write ( ByteBuffer src ) throws IOException {
123136 if ( !isHandShakeComplete () ) {
124137 processHandshake ();
125138 return 0 ;
126- } else {
127- return sc .write ( wrap ( src ) );
128139 }
140+ int num = sc .write ( wrap ( src ) );
141+ return num ;
142+
129143 }
130144
131145 public int read ( ByteBuffer dst ) throws IOException {
132146 if ( !isHandShakeComplete () ) {
133147 processHandshake ();
134148 return 0 ;
135149 }
136- int amount = 0 , limit ;
137- // test if there was a buffer overflow in dst
138- if ( inData .hasRemaining () ) {
139- return transfereTo ( inData , dst );
140- }
141- // test if some bytes left from last read (e.g. BUFFER_UNDERFLOW)
142- if ( inCrypt .hasRemaining () ) {
143- unwrap ();
144- amount += transfereTo ( inData , dst );
145- }
150+
151+ int purged = readRemaining ( dst );
152+ if ( purged != 0 )
153+ return purged ;
154+
155+ assert ( inData .position () == 0 );
156+ inData .clear ();
157+
146158 if ( !inCrypt .hasRemaining () )
147159 inCrypt .clear ();
148160 else
@@ -153,11 +165,28 @@ public int read( ByteBuffer dst ) throws IOException {
153165 }
154166 inCrypt .flip ();
155167 unwrap ();
156- amount += transfereTo ( inData , dst );
157- return amount ;
168+ return transfereTo ( inData , dst );
158169
159170 }
160171
172+ private int readRemaining ( ByteBuffer dst ) throws SSLException {
173+ assert ( dst .hasRemaining () );
174+
175+ if ( inData .hasRemaining () ) {
176+ return transfereTo ( inData , dst );
177+ }
178+ assert ( !inData .hasRemaining () );
179+ inData .clear ();
180+ // test if some bytes left from last read (e.g. BUFFER_UNDERFLOW)
181+ if ( inCrypt .hasRemaining () ) {
182+ unwrap ();
183+ int amount = transfereTo ( inData , dst );
184+ if ( amount > 0 )
185+ return amount ;
186+ }
187+ return 0 ;
188+ }
189+
161190 public boolean isConnected () {
162191 return sc .isConnected ();
163192 }
@@ -211,12 +240,12 @@ public void writeMore() throws IOException {
211240
212241 @ Override
213242 public boolean isNeedRead () {
214- return inData .hasRemaining ();
243+ return inData .hasRemaining () || ( inCrypt . hasRemaining () && res . getStatus () != Status . BUFFER_UNDERFLOW ) ;
215244 }
216245
217246 @ Override
218- public int readMore ( ByteBuffer dst ) {
219- return transfereTo ( inData , dst );
247+ public int readMore ( ByteBuffer dst ) throws SSLException {
248+ return readRemaining ( dst );
220249 }
221250
222251 private int transfereTo ( ByteBuffer from , ByteBuffer to ) {
0 commit comments