From 245c513fed1c946cb5b085fab0e424b28651cce3 Mon Sep 17 00:00:00 2001 From: Atsushi Watanabe Date: Sun, 5 Jul 2020 22:14:08 +0900 Subject: [PATCH] Fix turn client routine leak on close Clean-up turn connection if task run failed. --- gather.go | 9 +++++++-- gather_vnet_test.go | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+), 2 deletions(-) diff --git a/gather.go b/gather.go index 3ff7bdc..77107c3 100644 --- a/gather.go +++ b/gather.go @@ -415,11 +415,14 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { return locConn.Close() }, } - candidate, err := NewCandidateRelay(&relayConfig) - if err != nil { + relayConnClose := func() { if relayConErr := relayConn.Close(); relayConErr != nil { a.log.Warnf("Failed to close relay %v", relayConErr) } + } + candidate, err := NewCandidateRelay(&relayConfig) + if err != nil { + relayConnClose() client.Close() closeConnAndLog(locConn, a.log, fmt.Sprintf("Failed to create relay candidate: %s %s: %v\n", network, raddr.String(), err)) @@ -427,6 +430,8 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { } if err := a.addCandidate(ctx, candidate, relayConn); err != nil { + relayConnClose() + if closeErr := candidate.close(); closeErr != nil { a.log.Warnf("Failed to close candidate: %v", closeErr) } diff --git a/gather_vnet_test.go b/gather_vnet_test.go index 38330cf..1d5d312 100644 --- a/gather_vnet_test.go +++ b/gather_vnet_test.go @@ -3,6 +3,7 @@ package ice import ( + "context" "fmt" "net" "testing" @@ -412,3 +413,47 @@ func TestVNetGatherWithInterfaceFilter(t *testing.T) { assert.NoError(t, a.Close()) }) } + +func TestVNetGather_TURNConnectionLeak(t *testing.T) { + report := test.CheckRoutines(t) + defer report() + + turnServerURL := &URL{ + Scheme: SchemeTypeTURN, + Host: vnetSTUNServerIP, + Port: vnetSTUNServerPort, + Username: "user", + Password: "pass", + Proto: ProtoTypeUDP, + } + + // buildVNet with a Symmetric NATs for both LANs + natType := &vnet.NATType{ + MappingBehavior: vnet.EndpointAddrPortDependent, + FilteringBehavior: vnet.EndpointAddrPortDependent, + } + v, err := buildVNet(natType, natType) + + if !assert.NoError(t, err, "should succeed") { + return + } + defer v.close() + + cfg0 := &AgentConfig{ + Urls: []*URL{ + turnServerURL, + }, + NetworkTypes: supportedNetworkTypes, + MulticastDNSMode: MulticastDNSModeDisabled, + NAT1To1IPs: []string{vnetGlobalIPA}, + Net: v.net0, + } + aAgent, err := NewAgent(cfg0) + if !assert.NoError(t, err, "should succeed") { + return + } + + aAgent.gatherCandidatesRelay(context.Background(), []*URL{turnServerURL}) + // Assert relay conn leak on close. + assert.NoError(t, aAgent.Close()) +}