Skip to content

Commit c0f85ab

Browse files
committed
TUN-5956: Add timeout to session manager APIs
1 parent c5d1662 commit c0f85ab

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

datagramsession/manager.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package datagramsession
33
import (
44
"context"
55
"io"
6+
"time"
67

78
"github.com/google/uuid"
89
"github.com/lucas-clemente/quic-go"
@@ -12,6 +13,7 @@ import (
1213

1314
const (
1415
requestChanCapacity = 16
16+
defaultReqTimeout = time.Second * 5
1517
)
1618

1719
// Manager defines the APIs to manage sessions from the same transport.
@@ -31,9 +33,11 @@ type manager struct {
3133
transport transport
3234
sessions map[uuid.UUID]*Session
3335
log *zerolog.Logger
36+
// timeout waiting for an API to finish. This can be overriden in test
37+
timeout time.Duration
3438
}
3539

36-
func NewManager(transport transport, log *zerolog.Logger) Manager {
40+
func NewManager(transport transport, log *zerolog.Logger) *manager {
3741
return &manager{
3842
registrationChan: make(chan *registerSessionEvent),
3943
unregistrationChan: make(chan *unregisterSessionEvent),
@@ -42,6 +46,7 @@ func NewManager(transport transport, log *zerolog.Logger) Manager {
4246
transport: transport,
4347
sessions: make(map[uuid.UUID]*Session),
4448
log: log,
49+
timeout: defaultReqTimeout,
4550
}
4651
}
4752

@@ -89,9 +94,12 @@ func (m *manager) Serve(ctx context.Context) error {
8994
}
9095

9196
func (m *manager) RegisterSession(ctx context.Context, sessionID uuid.UUID, originProxy io.ReadWriteCloser) (*Session, error) {
97+
ctx, cancel := context.WithTimeout(ctx, m.timeout)
98+
defer cancel()
9299
event := newRegisterSessionEvent(sessionID, originProxy)
93100
select {
94101
case <-ctx.Done():
102+
m.log.Error().Msg("Datagram session registration timeout")
95103
return nil, ctx.Err()
96104
case m.registrationChan <- event:
97105
session := <-event.resultChan
@@ -106,6 +114,8 @@ func (m *manager) registerSession(ctx context.Context, registration *registerSes
106114
}
107115

108116
func (m *manager) UnregisterSession(ctx context.Context, sessionID uuid.UUID, message string, byRemote bool) error {
117+
ctx, cancel := context.WithTimeout(ctx, m.timeout)
118+
defer cancel()
109119
event := &unregisterSessionEvent{
110120
sessionID: sessionID,
111121
err: &errClosedSession{
@@ -115,6 +125,7 @@ func (m *manager) UnregisterSession(ctx context.Context, sessionID uuid.UUID, me
115125
}
116126
select {
117127
case <-ctx.Done():
128+
m.log.Error().Msg("Datagram session unregistration timeout")
118129
return ctx.Err()
119130
case m.unregistrationChan <- event:
120131
return nil

datagramsession/manager_test.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,28 @@ func TestManagerServe(t *testing.T) {
120120
<-serveDone
121121
}
122122

123+
func TestTimeout(t *testing.T) {
124+
const (
125+
testTimeout = time.Millisecond * 50
126+
)
127+
log := zerolog.Nop()
128+
transport := &mockQUICTransport{
129+
reqChan: newDatagramChannel(1),
130+
respChan: newDatagramChannel(1),
131+
}
132+
mg := NewManager(transport, &log)
133+
mg.timeout = testTimeout
134+
ctx := context.Background()
135+
sessionID := uuid.New()
136+
// session manager is not running, so event loop is not running and therefore calling the APIs should timeout
137+
session, err := mg.RegisterSession(ctx, sessionID, nil)
138+
require.ErrorIs(t, err, context.DeadlineExceeded)
139+
require.Nil(t, session)
140+
141+
err = mg.UnregisterSession(ctx, sessionID, "session gone", true)
142+
require.ErrorIs(t, err, context.DeadlineExceeded)
143+
}
144+
123145
type mockOrigin struct {
124146
expectMsgCount int
125147
expectedMsg []byte

0 commit comments

Comments
 (0)