Skip to content

Commit 7a1d05f

Browse files
author
Zhen
committed
Added an exception for Closed status in unwrap(write) method to indicate that we failed to write due to encrypted channel closed either by server or client
Extracted a few methods out for better code
1 parent dfc1e77 commit 7a1d05f

File tree

2 files changed

+94
-75
lines changed

2 files changed

+94
-75
lines changed

driver/src/main/java/org/neo4j/driver/internal/security/TLSSocketChannel.java

Lines changed: 92 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -133,11 +133,11 @@ private void runHandshake() throws IOException
133133
handshakeStatus = runDelegatedTasks();
134134
break;
135135
case NEED_UNWRAP:
136-
// Unwrap the ssl packet to value ssl handshake information
136+
// Unwrap the ssl packet to obtain ssl handshake status. The content of the message is not needed.
137137
handshakeStatus = unwrap( DUMMY_BUFFER );
138138
break;
139139
case NEED_WRAP:
140-
// Wrap the app packet into an ssl packet to add ssl handshake information
140+
// Wrap the app packet into an ssl packet to send ssl handshake to server
141141
handshakeStatus = wrap( plainOut );
142142
break;
143143
}
@@ -248,7 +248,7 @@ private HandshakeStatus unwrap( ByteBuffer buffer ) throws IOException
248248
/* In normal situations, enlarging buffers should happen very very rarely, as usually,
249249
the initial size for application buffer and network buffer is greater than 1024 * 10,
250250
and by using ChunkedInput and ChunkedOutput, the chunks are limited to 8192.
251-
So we should not value any enlarging buffer request in most cases. */
251+
So we should not have any buffer enlarging request in most cases. */
252252
switch ( status )
253253
{
254254
case OK:
@@ -258,54 +258,20 @@ private HandshakeStatus unwrap( ByteBuffer buffer ) throws IOException
258258
handshakeStatus = runDelegatedTasks();
259259
break;
260260
case BUFFER_OVERFLOW:
261-
plainIn.flip();
262-
// Could attempt to drain the plainIn buffer of any already obtained
263-
// data, but we'll just increase it to the size needed.
264-
int curAppSize = plainIn.capacity();
265-
int appSize = sslEngine.getSession().getApplicationBufferSize();
266-
int newAppSize = appSize + plainIn.remaining();
267-
if ( newAppSize > appSize * 2 )
268-
{
269-
throw new ClientException(
270-
format( "Failed ro enlarge application input buffer from %s to %s, as the maximum " +
271-
"buffer size allowed is %s. The content in the buffer is: %s\n",
272-
curAppSize, newAppSize, appSize * 2, BytePrinter.hex( plainIn ) ) );
273-
}
274-
ByteBuffer newPlainIn = ByteBuffer.allocate( newAppSize );
275-
newPlainIn.put( plainIn );
276-
plainIn = newPlainIn;
277-
logger.debug( "Enlarged application input buffer from %s to %s. " +
278-
"This operation should be a rare operation.", curAppSize, newAppSize );
279-
// retry the operation.
280-
break;
261+
enlargeApplicationInputBuffer();
262+
break; // retry the operation.
281263
case BUFFER_UNDERFLOW:
282-
int curNetSize = cipherIn.capacity();
283-
int netSize = sslEngine.getSession().getPacketBufferSize();
284-
// Resize buffer if needed.
285-
if ( netSize > curNetSize )
286-
{
287-
ByteBuffer newCipherIn = ByteBuffer.allocate( netSize );
288-
newCipherIn.put( cipherIn );
289-
cipherIn = newCipherIn;
290-
logger.debug( "Enlarged network input buffer from %s to %s. " +
291-
"This operation should be a rare operation.", curNetSize, netSize );
292-
}
293-
else
294-
{
295-
// Otherwise, make room for reading more data from channel
296-
cipherIn.compact();
297-
}
298-
return handshakeStatus; // old status
264+
enlargeNetworkInputBuffer();
265+
return handshakeStatus; // return directly and require read more bytes from network channel to continue
299266
case CLOSED:
300267
// RFC 2246 #7.2.1 requires us to stop accepting input.
301268
sslEngine.closeInbound();
302269
break;
303270
default:
304-
throw new ClientException( "Got unexpected status " + status + ", " + unwrapResult );
271+
throw new ClientException( "Got unexpected status " + status + " while reading encrypted data.");
305272
}
306273
}
307-
while ( cipherIn.hasRemaining() ); /* Remember we are doing blocking reading.
308-
We expect we should first handle all the data we've got and then decide what to do next. */
274+
while ( cipherIn.hasRemaining() );
309275

310276
cipherIn.compact();
311277
return handshakeStatus;
@@ -339,38 +305,13 @@ private HandshakeStatus wrap( ByteBuffer buffer ) throws IOException, ClientExce
339305
cipherOut.clear();
340306
break;
341307
case BUFFER_OVERFLOW:
342-
// Enlarge the buffer and return the old status
343-
int curNetSize = cipherOut.capacity();
344-
int netSize = sslEngine.getSession().getPacketBufferSize();
345-
if ( netSize > curNetSize )
346-
{
347-
// enlarge the peer application data buffer
348-
cipherOut = ByteBuffer.allocate( netSize );
349-
logger.debug( "Enlarged network output buffer from %s to %s. " +
350-
"This operation should be a rare operation.", curNetSize, netSize );
351-
}
352-
else
353-
{
354-
logger.debug( "Network output buffer doesn't need enlarging, flushing data to the channel instead to open up space on the buffer." );
355-
// flush as much data as possible
356-
cipherOut.flip();
357-
while ( cipherOut.hasRemaining() ) {
358-
int written = channelWrite( cipherOut );
359-
360-
if (written > 0) {
361-
break;
362-
}
363-
364-
logger.debug( "having difficulty flushing data (network contention on local computer?). will continue trying after yielding execution." );
365-
Thread.yield();
366-
367-
logger.debug( "nothing written to the underlying channel (network output buffer is full?), will try till we can." );
368-
}
369-
cipherOut.compact();
370-
}
308+
enlargeNetworkOutBuffer();
371309
break;
310+
case CLOSED:
311+
sslEngine.closeOutbound();
312+
throw new ServiceUnavailableException( "Encrypted connection closed while writing encrypted data." );
372313
default:
373-
throw new ClientException( "Got unexpected status " + status );
314+
throw new ClientException( "Got unexpected status " + status + " while writing encrypted data." );
374315
}
375316
return handshakeStatus;
376317
}
@@ -407,7 +348,10 @@ private static int bufferCopy( ByteBuffer from, ByteBuffer to )
407348
return maxTransfer;
408349
}
409350

351+
410352
@Override
353+
// try to read and return how many bytes have been read
354+
// throw exception when failed to continue read more while expecting more to read
411355
public int read( ByteBuffer dst ) throws IOException
412356
{
413357
/**
@@ -488,6 +432,81 @@ public void close() throws IOException
488432
}
489433
}
490434

435+
private void enlargeNetworkInputBuffer()
436+
{
437+
int curNetSize = cipherIn.capacity();
438+
int netSize = sslEngine.getSession().getPacketBufferSize();
439+
// Resize buffer if needed.
440+
if ( netSize > curNetSize )
441+
{
442+
ByteBuffer newCipherIn = ByteBuffer.allocate( netSize );
443+
newCipherIn.put( cipherIn );
444+
cipherIn = newCipherIn;
445+
logger.debug( "Enlarged network input buffer from %s to %s. " +
446+
"This operation should be a rare operation.", curNetSize, netSize );
447+
}
448+
else
449+
{
450+
// Otherwise, make room for reading more data from channel
451+
cipherIn.compact();
452+
}
453+
}
454+
455+
private void enlargeApplicationInputBuffer()
456+
{
457+
plainIn.flip();
458+
// Could attempt to drain the plainIn buffer of any already obtained
459+
// data, but we'll just increase it to the size needed.
460+
int curAppSize = plainIn.capacity();
461+
int appSize = sslEngine.getSession().getApplicationBufferSize();
462+
int newAppSize = appSize + plainIn.remaining();
463+
if ( newAppSize > appSize * 2 )
464+
{
465+
throw new ClientException(
466+
format( "Failed ro enlarge application input buffer from %s to %s, as the maximum " +
467+
"buffer size allowed is %s. The content in the buffer is: %s\n",
468+
curAppSize, newAppSize, appSize * 2, BytePrinter.hex( plainIn ) ) );
469+
}
470+
ByteBuffer newPlainIn = ByteBuffer.allocate( newAppSize );
471+
newPlainIn.put( plainIn );
472+
plainIn = newPlainIn;
473+
logger.debug( "Enlarged application input buffer from %s to %s. " +
474+
"This operation should be a rare operation.", curAppSize, newAppSize );
475+
}
476+
477+
private void enlargeNetworkOutBuffer() throws IOException
478+
{
479+
// Enlarge the buffer and return the old status
480+
int curNetSize = cipherOut.capacity();
481+
int netSize = sslEngine.getSession().getPacketBufferSize();
482+
if ( netSize > curNetSize )
483+
{
484+
// enlarge the peer application data buffer
485+
cipherOut = ByteBuffer.allocate( netSize );
486+
logger.debug( "Enlarged network output buffer from %s to %s. " +
487+
"This operation should be a rare operation.", curNetSize, netSize );
488+
}
489+
else
490+
{
491+
logger.debug( "Network output buffer doesn't need enlarging, flushing data to the channel instead to open up space on the buffer." );
492+
// flush as much data as possible
493+
cipherOut.flip();
494+
while ( cipherOut.hasRemaining() ) {
495+
int written = channelWrite( cipherOut );
496+
497+
if (written > 0) {
498+
break;
499+
}
500+
501+
logger.debug( "having difficulty flushing data (network contention on local computer?). will continue trying after yielding execution." );
502+
Thread.yield();
503+
504+
logger.debug( "nothing written to the underlying channel (network output buffer is full?), will try till we can." );
505+
}
506+
cipherOut.compact();
507+
}
508+
}
509+
491510
@Override
492511
public String toString()
493512
{

driver/src/test/java/org/neo4j/driver/v1/integration/TLSSocketChannelFragmentation.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,14 +95,14 @@ public void shouldHandleFuzziness() throws Throwable
9595
for ( int dataBlobMagnitude = 1; dataBlobMagnitude < 16; dataBlobMagnitude += 2 )
9696
{
9797
blobOfDataSize = (int) Math.pow( 2, dataBlobMagnitude );
98-
blobOfData = blobOfData( blobOfDataSize );
9998

10099
for ( int frameSizeMagnitude = 1; frameSizeMagnitude < 16; frameSizeMagnitude += 2 )
101100
{
102101
networkFrameSize = (int) Math.pow( 2, frameSizeMagnitude );
103102
for ( int userBufferMagnitude = 1; userBufferMagnitude < 16; userBufferMagnitude += 2 )
104103
{
105104
userBufferSize = (int) Math.pow( 2, userBufferMagnitude );
105+
blobOfData = blobOfData( blobOfDataSize );
106106
testForBufferSizes( blobOfData, networkFrameSize, userBufferSize );
107107
}
108108
}
@@ -168,7 +168,7 @@ static byte[] blobOfData( int dataBlobSize )
168168
// fill the data blob with different values.
169169
for ( int i = 0; i < blobOfData.length; i++ )
170170
{
171-
blobOfData[i] = (byte) (i % 128);
171+
blobOfData[i] = (byte) ((System.currentTimeMillis() + i) % 128);
172172
}
173173

174174
return blobOfData;

0 commit comments

Comments
 (0)