From 9a71f6981fd072c1a22650b027f61a91d13e2823 Mon Sep 17 00:00:00 2001 From: Eric Daniels Date: Wed, 4 Sep 2024 12:40:30 -0400 Subject: [PATCH] Prevent ICETransport start/stop deadlock --- errors.go | 1 + icetransport.go | 23 +++++++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/errors.go b/errors.go index 009e91dd681..8c460d14442 100644 --- a/errors.go +++ b/errors.go @@ -240,6 +240,7 @@ var ( errInvalidICEServer = errors.New("invalid ICEServer") errICETransportNotInNew = errors.New("ICETransport can only be called in ICETransportStateNew") + errICETransportClosed = errors.New("ICETransport closed") errCertificatePEMFormatError = errors.New("bad Certificate PEM format") diff --git a/icetransport.go b/icetransport.go index 8f743bc04f2..d92b346070c 100644 --- a/icetransport.go +++ b/icetransport.go @@ -157,6 +157,10 @@ func (t *ICETransport) Start(gatherer *ICEGatherer, params ICEParameters, role * return err } + if t.State() == ICETransportStateClosed { + return errICETransportClosed + } + t.conn = iceConn config := mux.Config{ @@ -200,28 +204,31 @@ func (t *ICETransport) GracefulStop() error { func (t *ICETransport) stop(shouldGracefullyClose bool) error { t.lock.Lock() - defer t.lock.Unlock() - t.setState(ICETransportStateClosed) if t.ctxCancel != nil { t.ctxCancel() } + // mux and gatherer can only be set when ICETransport.State != Closed. + mux := t.mux + gatherer := t.gatherer + t.lock.Unlock() + if t.mux != nil { var closeErrs []error - if shouldGracefullyClose && t.gatherer != nil { + if shouldGracefullyClose && gatherer != nil { // we can't access icegatherer/icetransport.Close via // mux's net.Conn Close so we call it earlier here. - closeErrs = append(closeErrs, t.gatherer.GracefulClose()) + closeErrs = append(closeErrs, gatherer.GracefulClose()) } - closeErrs = append(closeErrs, t.mux.Close()) + closeErrs = append(closeErrs, mux.Close()) return util.FlattenErrs(closeErrs) - } else if t.gatherer != nil { + } else if gatherer != nil { if shouldGracefullyClose { - return t.gatherer.GracefulClose() + return gatherer.GracefulClose() } - return t.gatherer.Close() + return gatherer.Close() } return nil }