@@ -21,6 +21,7 @@ type Stream* = ref object
2121 quicStream* : ptr lsquic_stream_t
2222 closedByEngine* : bool
2323 closeWrite* : bool
24+ closeRequested: bool
2425 # This is called when on_close callback is executed
2526 closed* : AsyncEvent
2627 # Reuse a single closed-event waiter to minimize allocations on hot paths.
@@ -132,23 +133,39 @@ template raiseIfWriteReset(stream: Stream) =
132133 if stream.writeResetByPeer ():
133134 raise stream.newStreamResetError (" stream write" )
134135
135- proc abort * (stream: Stream ) =
136+ proc requestClose (stream: Stream ): bool {.raises : [].} =
137+ if stream.closedByEngine or stream.quicStream.isNil or stream.closeRequested:
138+ return true
139+
140+ stream.closeRequested = true
141+ let ret = lsquic_stream_close (stream.quicStream)
142+ if ret != 0 :
143+ let closeErrno = errno
144+ if closeErrno == EBADF :
145+ stream.doProcess ()
146+ return true
147+
148+ stream.closeRequested = false
149+ trace " could not close stream" ,
150+ streamId = lsquic_stream_id (stream.quicStream), errno = closeErrno
151+ return false
152+
153+ stream.doProcess ()
154+ true
155+
156+ proc closeIfDone * (stream: Stream ): bool {.raises : [].} =
136157 if stream.closeWrite and stream.isEof:
137- if not stream.closed.isSet ():
138- stream.closed.fire ()
139- stream.abortPendingWrites (" stream aborted" )
140- return
158+ return stream.requestClose ()
141159
142- if not stream.closedByEngine:
143- let ret = lsquic_stream_close (stream.quicStream)
144- if ret != 0 :
145- trace " could not abort stream" , streamId = lsquic_stream_id (stream.quicStream)
146- stream.doProcess ()
160+ true
147161
162+ proc abort * (stream: Stream ) =
148163 stream.closeWrite = true
149164 stream.isEof = true
165+ discard stream.requestClose ()
150166 stream.abortPendingWrites (" stream aborted" )
151- stream.closed.fire ()
167+ if not stream.closed.isSet ():
168+ stream.closed.fire ()
152169
153170proc close * (stream: Stream ) {.async : (raises: [StreamError , CancelledError ]).} =
154171 if stream.closeWrite or stream.closedByEngine:
@@ -157,14 +174,13 @@ proc close*(stream: Stream) {.async: (raises: [StreamError, CancelledError]).} =
157174 # Closing only the write side
158175 let ret = lsquic_stream_shutdown (stream.quicStream, 1 )
159176 if ret == 0 :
160- if stream.isEof:
161- if lsquic_stream_close (stream.quicStream) != 0 :
162- stream.abort ()
163- raise newException (StreamError , " could not close the stream" )
164-
165177 stream.abortPendingWrites (" stream closed" )
166178 stream.closeWrite = true
167- stream.doProcess ()
179+ if not stream.closeIfDone ():
180+ stream.abort ()
181+ raise newException (StreamError , " could not close the stream" )
182+ if not stream.isEof:
183+ stream.doProcess ()
168184 else :
169185 raise newException (StreamError , " could not close the stream" )
170186
@@ -200,6 +216,9 @@ proc readOnce*(
200216
201217 if n == 0 :
202218 stream.isEof = true
219+ if not stream.closeIfDone ():
220+ stream.abort ()
221+ raise newException (StreamError , " could not close the stream" )
203222 return 0
204223 elif n > 0 :
205224 return n
@@ -231,6 +250,7 @@ proc readOnce*(
231250 raiseIfReadReset (stream)
232251 stream.isEof = true
233252 stream.closeWrite = true
253+ discard stream.closeIfDone ()
234254 return 0
235255
236256 return await doneFut
0 commit comments