@@ -42,6 +42,9 @@ type bindingRequest struct {
4242type Agent struct {
4343 loop * taskloop.Loop
4444
45+ startedCandidatesMu sync.Mutex
46+ startedCandidates map [* candidateBase ]struct {}
47+
4548 // constructed is set to true after the agent is fully initialized.
4649 // Options can check this flag to reject updates that are only valid during construction.
4750 constructed bool
@@ -353,6 +356,7 @@ func createAgentBase(config *AgentConfig) (*Agent, error) {
353356 lite : config .Lite ,
354357 gatheringState : GatheringStateNew ,
355358 connectionState : ConnectionStateNew ,
359+ startedCandidates : make (map [* candidateBase ]struct {}),
356360 localCandidates : make (map [NetworkType ][]Candidate ),
357361 remoteCandidates : make (map [NetworkType ][]Candidate ),
358362 pairsByID : make (map [uint64 ]* CandidatePair ),
@@ -1485,7 +1489,7 @@ func (a *Agent) GracefulClose() error {
14851489
14861490func (a * Agent ) close (graceful bool ) error {
14871491 // the loop is safe to wait on no matter what
1488- a .loop .Close ( )
1492+ a .loop .CloseWithPreStop ( a . abortStartedCandidateIO )
14891493
14901494 // but we are in less control of the notifiers, so we will
14911495 // pass through `graceful`.
@@ -1496,6 +1500,36 @@ func (a *Agent) close(graceful bool) error {
14961500 return nil
14971501}
14981502
1503+ func (a * Agent ) registerStartedCandidate (c * candidateBase ) {
1504+ a .startedCandidatesMu .Lock ()
1505+ defer a .startedCandidatesMu .Unlock ()
1506+
1507+ if a .startedCandidates == nil {
1508+ a .startedCandidates = make (map [* candidateBase ]struct {})
1509+ }
1510+ a .startedCandidates [c ] = struct {}{}
1511+ }
1512+
1513+ func (a * Agent ) unregisterStartedCandidate (c * candidateBase ) {
1514+ a .startedCandidatesMu .Lock ()
1515+ defer a .startedCandidatesMu .Unlock ()
1516+
1517+ delete (a .startedCandidates , c )
1518+ }
1519+
1520+ func (a * Agent ) abortStartedCandidateIO () {
1521+ a .startedCandidatesMu .Lock ()
1522+ candidates := make ([]* candidateBase , 0 , len (a .startedCandidates ))
1523+ for c := range a .startedCandidates {
1524+ candidates = append (candidates , c )
1525+ }
1526+ a .startedCandidatesMu .Unlock ()
1527+
1528+ for _ , c := range candidates {
1529+ _ = c .abortIO ()
1530+ }
1531+ }
1532+
14991533// Remove all candidates. This closes any listening sockets
15001534// and removes both the local and remote candidate lists.
15011535//
0 commit comments