Skip to content

Commit d8cf4e7

Browse files
committed
send GoAway on Close
1 parent e7338b0 commit d8cf4e7

File tree

2 files changed

+23
-4
lines changed

2 files changed

+23
-4
lines changed

const.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package yamux
33
import (
44
"encoding/binary"
55
"fmt"
6+
"time"
67
)
78

89
const (
@@ -52,6 +53,7 @@ const (
5253
// It's not an implementation choice, the value defined in the specification.
5354
initialStreamWindow = 256 * 1024
5455
maxStreamWindow = 16 * 1024 * 1024
56+
goAwayWaitTime = 5 * time.Second
5557
)
5658

5759
const (

session.go

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,8 +284,14 @@ func (s *Session) AcceptStream() (*Stream, error) {
284284
}
285285

286286
// Close is used to close the session and all streams.
287-
// Attempts to send a GoAway before closing the connection.
287+
// Attempts to send a GoAway before closing the connection. The GoAway may not actually be sent depending on the
288+
// semantics of the underlying net.Conn. For TCP connections, it may be dropped depending on LINGER value or
289+
// if there's unread data in the kernel receive buffer.
288290
func (s *Session) Close() error {
291+
return s.close(true, goAwayNormal)
292+
}
293+
294+
func (s *Session) close(sendGoAway bool, errCode uint32) error {
289295
s.shutdownLock.Lock()
290296
defer s.shutdownLock.Unlock()
291297

@@ -297,10 +303,21 @@ func (s *Session) Close() error {
297303
s.shutdownErr = ErrSessionShutdown
298304
}
299305
close(s.shutdownCh)
300-
s.conn.Close()
301306
s.stopKeepalive()
302-
<-s.recvDoneCh
307+
308+
// wait for write loop to exit
309+
_ = s.conn.SetWriteDeadline(time.Now().Add(-1 * time.Hour)) // if SetWriteDeadline errored, any blocked writes will be unblocked
303310
<-s.sendDoneCh
311+
if sendGoAway {
312+
ga := s.goAway(errCode)
313+
if err := s.conn.SetWriteDeadline(time.Now().Add(goAwayWaitTime)); err == nil {
314+
_, _ = s.conn.Write(ga[:]) // there's nothing we can do on error here
315+
}
316+
}
317+
318+
s.conn.SetWriteDeadline(time.Time{})
319+
s.conn.Close()
320+
<-s.recvDoneCh
304321

305322
s.streamLock.Lock()
306323
defer s.streamLock.Unlock()
@@ -320,7 +337,7 @@ func (s *Session) exitErr(err error) {
320337
s.shutdownErr = err
321338
}
322339
s.shutdownLock.Unlock()
323-
s.Close()
340+
s.close(false, 0)
324341
}
325342

326343
// GoAway can be used to prevent accepting further

0 commit comments

Comments
 (0)