@@ -41,6 +41,7 @@ type Stream struct {
4141
4242 state streamState
4343 writeState , readState halfStreamState
44+ writeErr , readErr error
4445 stateLock sync.Mutex
4546
4647 recvBuf segmentedBuffer
@@ -89,6 +90,7 @@ func (s *Stream) Read(b []byte) (n int, err error) {
8990START:
9091 s .stateLock .Lock ()
9192 state := s .readState
93+ resetErr := s .readErr
9294 s .stateLock .Unlock ()
9395
9496 switch state {
@@ -101,7 +103,7 @@ START:
101103 }
102104 // Closed, but we have data pending -> read.
103105 case halfReset :
104- return 0 , ErrStreamReset
106+ return 0 , resetErr
105107 default :
106108 panic ("unknown state" )
107109 }
@@ -147,6 +149,7 @@ func (s *Stream) write(b []byte) (n int, err error) {
147149START:
148150 s .stateLock .Lock ()
149151 state := s .writeState
152+ resetErr := s .writeErr
150153 s .stateLock .Unlock ()
151154
152155 switch state {
@@ -155,7 +158,7 @@ START:
155158 case halfClosed :
156159 return 0 , ErrStreamClosed
157160 case halfReset :
158- return 0 , ErrStreamReset
161+ return 0 , resetErr
159162 default :
160163 panic ("unknown state" )
161164 }
@@ -250,13 +253,17 @@ func (s *Stream) sendClose() error {
250253}
251254
252255// sendReset is used to send a RST
253- func (s * Stream ) sendReset () error {
254- hdr := encode (typeWindowUpdate , flagRST , s .id , 0 )
256+ func (s * Stream ) sendReset (errCode uint32 ) error {
257+ hdr := encode (typeWindowUpdate , flagRST , s .id , errCode )
255258 return s .session .sendMsg (hdr , nil , nil )
256259}
257260
258261// Reset resets the stream (forcibly closes the stream)
259262func (s * Stream ) Reset () error {
263+ return s .ResetWithError (0 )
264+ }
265+
266+ func (s * Stream ) ResetWithError (errCode uint32 ) error {
260267 sendReset := false
261268 s .stateLock .Lock ()
262269 switch s .state {
@@ -276,15 +283,17 @@ func (s *Stream) Reset() error {
276283 // If we've already sent/received an EOF, no need to reset that side.
277284 if s .writeState == halfOpen {
278285 s .writeState = halfReset
286+ s .writeErr = & StreamError {Remote : false , ErrorCode : errCode }
279287 }
280288 if s .readState == halfOpen {
281289 s .readState = halfReset
290+ s .readErr = & StreamError {Remote : false , ErrorCode : errCode }
282291 }
283292 s .state = streamFinished
284293 s .notifyWaiting ()
285294 s .stateLock .Unlock ()
286295 if sendReset {
287- _ = s .sendReset ()
296+ _ = s .sendReset (errCode )
288297 }
289298 s .cleanup ()
290299 return nil
@@ -336,6 +345,7 @@ func (s *Stream) CloseRead() error {
336345 panic ("invalid state" )
337346 }
338347 s .readState = halfReset
348+ s .readErr = ErrStreamReset
339349 cleanup = s .writeState != halfOpen
340350 if cleanup {
341351 s .state = streamFinished
@@ -357,13 +367,15 @@ func (s *Stream) Close() error {
357367}
358368
359369// forceClose is used for when the session is exiting
360- func (s * Stream ) forceClose () {
370+ func (s * Stream ) forceClose (err error ) {
361371 s .stateLock .Lock ()
362372 if s .readState == halfOpen {
363373 s .readState = halfReset
374+ s .readErr = err
364375 }
365376 if s .writeState == halfOpen {
366377 s .writeState = halfReset
378+ s .writeErr = err
367379 }
368380 s .state = streamFinished
369381 s .notifyWaiting ()
@@ -382,7 +394,7 @@ func (s *Stream) cleanup() {
382394
383395// processFlags is used to update the state of the stream
384396// based on set flags, if any. Lock must be held
385- func (s * Stream ) processFlags (flags uint16 ) {
397+ func (s * Stream ) processFlags (flags uint16 , hdr header ) {
386398 // Close the stream without holding the state lock
387399 var closeStream bool
388400 defer func () {
@@ -418,11 +430,18 @@ func (s *Stream) processFlags(flags uint16) {
418430 }
419431 if flags & flagRST == flagRST {
420432 s .stateLock .Lock ()
433+ var resetErr error = ErrStreamReset
434+ // Length in a window update frame with RST flag encodes an error code.
435+ if hdr .MsgType () == typeWindowUpdate {
436+ resetErr = & StreamError {Remote : true , ErrorCode : hdr .Length ()}
437+ }
421438 if s .readState == halfOpen {
422439 s .readState = halfReset
440+ s .readErr = resetErr
423441 }
424442 if s .writeState == halfOpen {
425443 s .writeState = halfReset
444+ s .writeErr = resetErr
426445 }
427446 s .state = streamFinished
428447 s .stateLock .Unlock ()
@@ -439,15 +458,15 @@ func (s *Stream) notifyWaiting() {
439458
440459// incrSendWindow updates the size of our send window
441460func (s * Stream ) incrSendWindow (hdr header , flags uint16 ) {
442- s .processFlags (flags )
461+ s .processFlags (flags , hdr )
443462 // Increase window, unblock a sender
444463 atomic .AddUint32 (& s .sendWindow , hdr .Length ())
445464 asyncNotify (s .sendNotifyCh )
446465}
447466
448467// readData is used to handle a data frame
449468func (s * Stream ) readData (hdr header , flags uint16 , conn io.Reader ) error {
450- s .processFlags (flags )
469+ s .processFlags (flags , hdr )
451470
452471 // Check that our recv window is not exceeded
453472 length := hdr .Length ()
0 commit comments