11/*
2- * Copyright (c) 2017, 2019 , Oracle and/or its affiliates. All rights reserved.
2+ * Copyright (c) 2017, 2026 , Oracle and/or its affiliates. All rights reserved.
33 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44 *
55 * This code is free software; you can redistribute it and/or modify it
@@ -268,7 +268,7 @@ final class Reader extends SubscriberWrapper implements FlowTube.TubeSubscriber
268268
269269 final SequentialScheduler scheduler ;
270270 volatile ByteBuffer readBuf ;
271- volatile boolean completing ;
271+ boolean completing ;
272272 final Object readBufferLock = new Object ();
273273 final Logger debugr = Utils .getDebugLogger (this ::dbgString , Utils .DEBUG );
274274
@@ -296,6 +296,11 @@ protected SchedulingAction enterScheduling() {
296296 return enterReadScheduling ();
297297 }
298298
299+ @ Override
300+ public boolean closing () {
301+ return closeNotifyReceived ();
302+ }
303+
299304 public final String dbgString () {
300305 return "SSL Reader(" + tubeName + ")" ;
301306 }
@@ -485,7 +490,7 @@ else if (this.completing) {
485490 if (result .handshaking ()) {
486491 handshaking = true ;
487492 if (debugr .on ()) debugr .log ("handshaking" );
488- if (doHandshake (result , READER )) continue ; // need unwrap
493+ if (doHandshake (result . handshakeStatus () , READER )) continue ; // need unwrap
489494 else break ; // doHandshake will have triggered the write scheduler if necessary
490495 } else {
491496 if (trySetALPN ()) {
@@ -525,6 +530,7 @@ else if (this.completing) {
525530
526531 private volatile Status lastUnwrapStatus ;
527532 EngineResult unwrapBuffer (ByteBuffer src ) throws IOException {
533+ assert Thread .holdsLock (readBufferLock );
528534 ByteBuffer dst = getAppBuffer ();
529535 int len = src .remaining ();
530536 while (true ) {
@@ -548,6 +554,8 @@ EngineResult unwrapBuffer(ByteBuffer src) throws IOException {
548554 break ;
549555 case CLOSED :
550556 assert dst .position () == 0 ;
557+ src .position (src .limit ());
558+ completing = true ;
551559 return doClosure (new EngineResult (sslResult ));
552560 case BUFFER_UNDERFLOW :
553561 // handled implicitly by compaction/reallocation of readBuf
@@ -808,7 +816,7 @@ private void processData() {
808816 boolean handshaking = false ;
809817 if (result .handshaking ()) {
810818 if (debugw .on ()) debugw .log ("handshaking" );
811- doHandshake (result , WRITER ); // ok to ignore return
819+ doHandshake (result . handshakeStatus () , WRITER ); // ok to ignore return
812820 handshaking = true ;
813821 } else {
814822 if (trySetALPN ()) {
@@ -1065,14 +1073,14 @@ private void resumeActivity() {
10651073 return (current & HANDSHAKING );
10661074 };
10671075
1068- private boolean doHandshake (EngineResult r , int caller ) {
1076+ private boolean doHandshake (HandshakeStatus handshakeStatus , int caller ) {
10691077 // unconditionally sets the HANDSHAKING bit, while preserving task bits
10701078 handshakeState .getAndAccumulate (0 , (current , unused ) -> HANDSHAKING | (current & TASK_BITS ));
10711079 if (stateList != null && debug .on ()) {
1072- stateList .add (r . handshakeStatus () .toString ());
1080+ stateList .add (handshakeStatus .toString ());
10731081 stateList .add (Integer .toString (caller ));
10741082 }
1075- switch (r . handshakeStatus () ) {
1083+ switch (handshakeStatus ) {
10761084 case NEED_TASK :
10771085 int s = handshakeState .accumulateAndGet (0 , REQUEST_OR_DO_TASKS );
10781086 if ((s & REQUESTING_TASKS ) > 0 ) { // someone else is or will do tasks
@@ -1100,7 +1108,7 @@ private boolean doHandshake(EngineResult r, int caller) {
11001108 break ;
11011109 default :
11021110 throw new InternalError ("Unexpected handshake status:"
1103- + r . handshakeStatus () );
1111+ + handshakeStatus );
11041112 }
11051113 return true ;
11061114 }
@@ -1157,30 +1165,20 @@ boolean trySetALPN() {
11571165 return false ;
11581166 }
11591167
1160- // FIXME: acknowledge a received CLOSE request from peer
11611168 EngineResult doClosure (EngineResult r ) throws IOException {
11621169 if (debug .on ())
11631170 debug .log ("doClosure(%s): %s [isOutboundDone: %s, isInboundDone: %s]" ,
11641171 r .result , engine .getHandshakeStatus (),
11651172 engine .isOutboundDone (), engine .isInboundDone ());
1173+ if (debug .on ()) debug .log ("doClosure: close_notify received" );
1174+ close_notify_received = true ;
1175+ engine .closeOutbound ();
11661176 if (engine .getHandshakeStatus () == HandshakeStatus .NEED_WRAP ) {
11671177 // we have received TLS close_notify and need to send
11681178 // an acknowledgement back. We're calling doHandshake
11691179 // to finish the close handshake.
1170- if (engine .isInboundDone () && !engine .isOutboundDone ()) {
1171- if (debug .on ()) debug .log ("doClosure: close_notify received" );
1172- close_notify_received = true ;
1173- if (!writer .scheduler .isStopped ()) {
1174- doHandshake (r , READER );
1175- } else {
1176- // We have received closed notify, but we
1177- // won't be able to send the acknowledgement.
1178- // Nothing more will come from the socket either,
1179- // so mark the reader as completed.
1180- synchronized (reader .readBufferLock ) {
1181- reader .completing = true ;
1182- }
1183- }
1180+ if (!writer .scheduler .isStopped ()) {
1181+ doHandshake (HandshakeStatus .NEED_WRAP , READER );
11841182 }
11851183 }
11861184 return r ;
0 commit comments