@@ -34,10 +34,11 @@ const (
3434
3535// QUICConnection represents the type that facilitates Proxying via QUIC streams.
3636type QUICConnection struct {
37- session quic.Session
38- logger * zerolog.Logger
39- httpProxy OriginProxy
40- sessionManager datagramsession.Manager
37+ session quic.Session
38+ logger * zerolog.Logger
39+ httpProxy OriginProxy
40+ sessionManager datagramsession.Manager
41+ controlStreamHandler ControlStreamHandler
4142}
4243
4344// NewQUICConnection returns a new instance of QUICConnection.
@@ -49,7 +50,7 @@ func NewQUICConnection(
4950 httpProxy OriginProxy ,
5051 connOptions * tunnelpogs.ConnectionOptions ,
5152 controlStreamHandler ControlStreamHandler ,
52- observer * Observer ,
53+ logger * zerolog. Logger ,
5354) (* QUICConnection , error ) {
5455 session , err := quic .DialAddr (edgeAddr .String (), tlsConfig , quicConfig )
5556 if err != nil {
@@ -72,34 +73,44 @@ func NewQUICConnection(
7273 return nil , err
7374 }
7475
75- sessionManager := datagramsession .NewManager (datagramMuxer , observer . log )
76+ sessionManager := datagramsession .NewManager (datagramMuxer , logger )
7677
7778 return & QUICConnection {
78- session : session ,
79- httpProxy : httpProxy ,
80- logger : observer .log ,
81- sessionManager : sessionManager ,
79+ session : session ,
80+ httpProxy : httpProxy ,
81+ logger : logger ,
82+ sessionManager : sessionManager ,
83+ controlStreamHandler : controlStreamHandler ,
8284 }, nil
8385}
8486
8587// Serve starts a QUIC session that begins accepting streams.
8688func (q * QUICConnection ) Serve (ctx context.Context ) error {
89+ // If either goroutine returns nil error, we rely on this cancellation to make sure the other goroutine exits
90+ // as fast as possible as well. Nil error means we want to exit for good (caller code won't retry serving this
91+ // connection).
92+ // If either goroutine returns a non nil error, then the error group cancels the context, thus also canceling the
93+ // other goroutine as fast as possible.
94+ ctx , cancel := context .WithCancel (ctx )
8795 errGroup , ctx := errgroup .WithContext (ctx )
8896 errGroup .Go (func () error {
97+ defer cancel ()
8998 return q .acceptStream (ctx )
9099 })
91100 errGroup .Go (func () error {
101+ defer cancel ()
92102 return q .sessionManager .Serve (ctx )
93103 })
94104 return errGroup .Wait ()
95105}
96106
97107func (q * QUICConnection ) acceptStream (ctx context.Context ) error {
108+ defer q .Close ()
98109 for {
99110 stream , err := q .session .AcceptStream (ctx )
100111 if err != nil {
101112 // context.Canceled is usually a user ctrl+c. We don't want to log an error here as it's intentional.
102- if errors .Is (err , context .Canceled ) {
113+ if errors .Is (err , context .Canceled ) || q . controlStreamHandler . IsStopped () {
103114 return nil
104115 }
105116 return fmt .Errorf ("failed to accept QUIC stream: %w" , err )
0 commit comments