@@ -87,6 +87,7 @@ public X509Certificate[] getAcceptedIssuers() {
8787 private SSLEngine sslEngine ;
8888 private int state = STATE_EMPTY ;
8989 private long unwrapInputBufferPtr ;
90+ private long unwrapOutputBufferPtr ;
9091 private long wrapOutputBufferPtr ;
9192
9293 JavaTlsClientSocket (NetworkFacade nf , Logger log , ClientTlsConfiguration tlsConfig ) {
@@ -167,60 +168,66 @@ public void of(int fd) {
167168 public int recv (long bufferPtr , int bufferLen ) {
168169 assert sslEngine != null ;
169170
170- resetBufferToPointer (unwrapOutputBuffer , bufferPtr , bufferLen );
171- unwrapOutputBuffer .position (0 );
172-
173171 try {
174- int plainBytesReceived = 0 ;
172+ if (unwrapOutputBuffer .position () != 0 ) {
173+ return drainUnwrapOutputBuffer (bufferPtr , bufferLen );
174+ }
175+
175176 for (; ; ) {
176177 int n = readFromSocket ();
177178 assert unwrapInputBuffer .position () == 0 : "unwrapInputBuffer is not compacted" ;
178179 int bytesAvailable = unwrapInputBuffer .limit ();
179180 if (n < 0 && bytesAvailable == 0 ) {
180- if (plainBytesReceived == 0 ) {
181- // we didn't manage to read anything from the socket, let's return the error
182- return n ;
183- }
184- // we have some data to return, let's return it
185- return plainBytesReceived ;
181+ return n ;
186182 }
187183
188184 if (bytesAvailable == 0 ) {
189185 // nothing to unwrap, we are done
190- return plainBytesReceived ;
186+ return 0 ;
191187 }
192188
193189 SSLEngineResult result = sslEngine .unwrap (unwrapInputBuffer , unwrapOutputBuffer );
194- plainBytesReceived += result .bytesProduced ();
195190
196191 // compact the TLS buffer
197192 int bytesConsumed = result .bytesConsumed ();
198193 int bytesRemaining = bytesAvailable - bytesConsumed ;
199- Vect .memcpy (unwrapInputBufferPtr , unwrapInputBufferPtr + bytesConsumed , bytesRemaining );
194+ if (bytesRemaining > 0 ) {
195+ Vect .memcpy (unwrapInputBufferPtr , unwrapInputBufferPtr + bytesConsumed , bytesRemaining );
196+ }
200197 unwrapInputBuffer .position (0 );
201198 unwrapInputBuffer .limit (bytesRemaining );
202199
203200 switch (result .getStatus ()) {
204201 case BUFFER_UNDERFLOW :
205- // we need more data to unwrap, let's return whatever we have
206- return plainBytesReceived ;
202+ if (unwrapOutputBuffer .position () != 0 ) {
203+ return drainUnwrapOutputBuffer (bufferPtr , bufferLen );
204+ }
205+ // we need more data to unwrap, let's return control to the caller
206+ return 0 ;
207207 case BUFFER_OVERFLOW :
208208 if (unwrapOutputBuffer .position () == 0 ) {
209209 // not even a single byte was written to the output buffer even the buffer is empty
210- throw new AssertionError ("Output buffer too small to fit a single TLS record. This should not happen, please report as a bug." );
210+ // apparently the output buffer cannot fit even a single TLS record. let's grow it and try again!
211+ growUnwrapOutputBuffer ();
212+ break ;
211213 }
212- // we have some data to return, let's return it
213- return plainBytesReceived ;
214+ return drainUnwrapOutputBuffer (bufferPtr , bufferLen );
214215 case OK :
215- break ;
216+ if (unwrapOutputBuffer .position () != 0 ) {
217+ return drainUnwrapOutputBuffer (bufferPtr , bufferLen );
218+ }
219+ return 0 ;
216220 case CLOSED :
217221 log .debug ("SSL engine closed" );
218222 // We received a TLS close notification from the server. We don't expect any further data from this connection.
219223 // If we have some previously unwrapped data then let's return it so the caller has a chance to process them.
220224 // If a caller calls recv() again and we have no remaining plaintext to return, we will return -1 so the
221225 // caller learned that the connection is closed.
222226 // If we have no plaintext data to return now then we can immediately indicate that we are done with the connection.
223- return plainBytesReceived == 0 ? -1 : plainBytesReceived ;
227+ if (unwrapOutputBuffer .position () == 0 ) {
228+ return -1 ;
229+ }
230+ return drainUnwrapOutputBuffer (bufferPtr , bufferLen );
224231 }
225232 }
226233 } catch (SSLException e ) {
@@ -303,9 +310,12 @@ public void startTlsSession(CharSequence peerName) throws TlsSessionInitFailedEx
303310 // there cannot be underflow since wrap() during handshake does not read from the input buffer at all
304311 throw new AssertionError ("Buffer underflow during TLS handshake. This should not happen. please report as a bug" );
305312 case BUFFER_OVERFLOW :
306- // in theory, this can happen if the output buffer is too small to fit a single TLS handshake record, but that would indicate
307- // our starting buffer is too small.
308- throw new AssertionError ("Buffer overflow during TLS handshake. This should not happen, please report as a bug" );
313+ if (wrapOutputBuffer .position () == 0 ) {
314+ // in theory, this can happen if the output buffer is too small to fit a single TLS handshake record,
315+ // but that would indicate our starting buffer is too small.
316+ growWrapOutputBuffer ();
317+ }
318+ break ;
309319 case OK :
310320 // wrapOutputBuffer: write mode
311321 int written = 0 ;
@@ -336,7 +346,12 @@ public void startTlsSession(CharSequence peerName) throws TlsSessionInitFailedEx
336346 // we need to receive more data from a socket, let's try again
337347 break ;
338348 case BUFFER_OVERFLOW :
339- throw new AssertionError ("Buffer overflow during TLS handshake. This should not happen, please report as a bug" );
349+ if (unwrapOutputBuffer .position () == 0 ) {
350+ // in theory, this can happen if the output buffer is too small to fit a single TLS handshake record,
351+ // but that would indicate our starting buffer is too small.
352+ growUnwrapOutputBuffer ();
353+ }
354+ break ;
340355 case OK :
341356 // good, let's see what we need to do next
342357 break ;
@@ -352,7 +367,8 @@ public void startTlsSession(CharSequence peerName) throws TlsSessionInitFailedEx
352367 unwrapInputBuffer .limit (0 );
353368
354369 // write mode and empty
355- unwrapOutputBuffer .clear ();
370+ unwrapOutputBuffer .position (0 );
371+ unwrapOutputBuffer .limit (unwrapOutputBuffer .capacity ());
356372 wrapOutputBuffer .clear ();
357373 state = STATE_TLS ;
358374 } catch (KeyManagementException | NoSuchAlgorithmException | KeyStoreException | IOException |
@@ -478,18 +494,42 @@ private void freeInternalBuffers() {
478494 ptrToFree = unwrapInputBufferPtr ;
479495 unwrapInputBufferPtr = 0 ;
480496 Unsafe .free (ptrToFree , capacity , MemoryTag .NATIVE_TLS_RSS );
497+
498+ capacity = unwrapOutputBuffer .capacity ();
499+ assert capacity != 0 ;
500+ resetBufferToPointer (unwrapOutputBuffer , 0 , 0 );
501+ ptrToFree = unwrapOutputBufferPtr ;
502+ unwrapOutputBufferPtr = 0 ;
503+ Unsafe .free (ptrToFree , capacity , MemoryTag .NATIVE_TLS_RSS );
481504 }
482505 }
483506
484507 private void growWrapOutputBuffer () {
485508 wrapOutputBufferPtr = expandBuffer (wrapOutputBuffer , wrapOutputBufferPtr );
486509 }
487510
511+ private void growUnwrapOutputBuffer () {
512+ unwrapOutputBufferPtr = expandBuffer (unwrapOutputBuffer , unwrapOutputBufferPtr );
513+ }
514+
488515 private void prepareInternalBuffers () {
489516 int initialCapacity = Integer .getInteger ("questdb.experimental.tls.buffersize" , INITIAL_BUFFER_CAPACITY_BYTES );
490517 this .wrapOutputBufferPtr = allocateMemoryAndResetBuffer (wrapOutputBuffer , initialCapacity );
491518 this .unwrapInputBufferPtr = allocateMemoryAndResetBuffer (unwrapInputBuffer , initialCapacity );
492519 unwrapInputBuffer .flip (); // read mode
520+ this .unwrapOutputBufferPtr = allocateMemoryAndResetBuffer (unwrapOutputBuffer , initialCapacity );
521+ }
522+
523+ private int drainUnwrapOutputBuffer (long bufferPtr , int bufferLen ) {
524+ unwrapOutputBuffer .flip ();
525+ int oldPosition = unwrapOutputBuffer .position ();
526+ int len = Math .min (bufferLen , unwrapOutputBuffer .remaining ());
527+ if (len > 0 ) {
528+ Vect .memcpy (bufferPtr , unwrapOutputBufferPtr + oldPosition , len );
529+ }
530+ unwrapOutputBuffer .position (oldPosition + len );
531+ unwrapOutputBuffer .compact ();
532+ return len ;
493533 }
494534
495535 private int readFromSocket () {
@@ -544,4 +584,4 @@ private int writeToSocket(int bytesToSend) {
544584 LIMIT_FIELD_OFFSET = Unsafe .getUnsafe ().objectFieldOffset (limitField );
545585 CAPACITY_FIELD_OFFSET = Unsafe .getUnsafe ().objectFieldOffset (capacityField );
546586 }
547- }
587+ }
0 commit comments