@@ -41,6 +41,7 @@ type Stream struct {
41
41
42
42
state streamState
43
43
writeState , readState halfStreamState
44
+ writeErr , readErr error
44
45
stateLock sync.Mutex
45
46
46
47
recvBuf segmentedBuffer
@@ -89,6 +90,7 @@ func (s *Stream) Read(b []byte) (n int, err error) {
89
90
START:
90
91
s .stateLock .Lock ()
91
92
state := s .readState
93
+ resetErr := s .readErr
92
94
s .stateLock .Unlock ()
93
95
94
96
switch state {
@@ -101,7 +103,7 @@ START:
101
103
}
102
104
// Closed, but we have data pending -> read.
103
105
case halfReset :
104
- return 0 , ErrStreamReset
106
+ return 0 , resetErr
105
107
default :
106
108
panic ("unknown state" )
107
109
}
@@ -147,6 +149,7 @@ func (s *Stream) write(b []byte) (n int, err error) {
147
149
START:
148
150
s .stateLock .Lock ()
149
151
state := s .writeState
152
+ resetErr := s .writeErr
150
153
s .stateLock .Unlock ()
151
154
152
155
switch state {
@@ -155,7 +158,7 @@ START:
155
158
case halfClosed :
156
159
return 0 , ErrStreamClosed
157
160
case halfReset :
158
- return 0 , ErrStreamReset
161
+ return 0 , resetErr
159
162
default :
160
163
panic ("unknown state" )
161
164
}
@@ -250,13 +253,17 @@ func (s *Stream) sendClose() error {
250
253
}
251
254
252
255
// 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 )
255
258
return s .session .sendMsg (hdr , nil , nil )
256
259
}
257
260
258
261
// Reset resets the stream (forcibly closes the stream)
259
262
func (s * Stream ) Reset () error {
263
+ return s .ResetWithError (0 )
264
+ }
265
+
266
+ func (s * Stream ) ResetWithError (errCode uint32 ) error {
260
267
sendReset := false
261
268
s .stateLock .Lock ()
262
269
switch s .state {
@@ -276,15 +283,17 @@ func (s *Stream) Reset() error {
276
283
// If we've already sent/received an EOF, no need to reset that side.
277
284
if s .writeState == halfOpen {
278
285
s .writeState = halfReset
286
+ s .writeErr = & StreamError {Remote : false , ErrorCode : errCode }
279
287
}
280
288
if s .readState == halfOpen {
281
289
s .readState = halfReset
290
+ s .readErr = & StreamError {Remote : false , ErrorCode : errCode }
282
291
}
283
292
s .state = streamFinished
284
293
s .notifyWaiting ()
285
294
s .stateLock .Unlock ()
286
295
if sendReset {
287
- _ = s .sendReset ()
296
+ _ = s .sendReset (errCode )
288
297
}
289
298
s .cleanup ()
290
299
return nil
@@ -336,6 +345,7 @@ func (s *Stream) CloseRead() error {
336
345
panic ("invalid state" )
337
346
}
338
347
s .readState = halfReset
348
+ s .readErr = ErrStreamReset
339
349
cleanup = s .writeState != halfOpen
340
350
if cleanup {
341
351
s .state = streamFinished
@@ -357,13 +367,15 @@ func (s *Stream) Close() error {
357
367
}
358
368
359
369
// forceClose is used for when the session is exiting
360
- func (s * Stream ) forceClose () {
370
+ func (s * Stream ) forceClose (err error ) {
361
371
s .stateLock .Lock ()
362
372
if s .readState == halfOpen {
363
373
s .readState = halfReset
374
+ s .readErr = err
364
375
}
365
376
if s .writeState == halfOpen {
366
377
s .writeState = halfReset
378
+ s .writeErr = err
367
379
}
368
380
s .state = streamFinished
369
381
s .notifyWaiting ()
@@ -382,7 +394,7 @@ func (s *Stream) cleanup() {
382
394
383
395
// processFlags is used to update the state of the stream
384
396
// 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 ) {
386
398
// Close the stream without holding the state lock
387
399
var closeStream bool
388
400
defer func () {
@@ -418,11 +430,18 @@ func (s *Stream) processFlags(flags uint16) {
418
430
}
419
431
if flags & flagRST == flagRST {
420
432
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
+ }
421
438
if s .readState == halfOpen {
422
439
s .readState = halfReset
440
+ s .readErr = resetErr
423
441
}
424
442
if s .writeState == halfOpen {
425
443
s .writeState = halfReset
444
+ s .writeErr = resetErr
426
445
}
427
446
s .state = streamFinished
428
447
s .stateLock .Unlock ()
@@ -439,15 +458,15 @@ func (s *Stream) notifyWaiting() {
439
458
440
459
// incrSendWindow updates the size of our send window
441
460
func (s * Stream ) incrSendWindow (hdr header , flags uint16 ) {
442
- s .processFlags (flags )
461
+ s .processFlags (flags , hdr )
443
462
// Increase window, unblock a sender
444
463
atomic .AddUint32 (& s .sendWindow , hdr .Length ())
445
464
asyncNotify (s .sendNotifyCh )
446
465
}
447
466
448
467
// readData is used to handle a data frame
449
468
func (s * Stream ) readData (hdr header , flags uint16 , conn io.Reader ) error {
450
- s .processFlags (flags )
469
+ s .processFlags (flags , hdr )
451
470
452
471
// Check that our recv window is not exceeded
453
472
length := hdr .Length ()
0 commit comments