diff --git a/go.mod b/go.mod index 88d2ffb5..e750843a 100644 --- a/go.mod +++ b/go.mod @@ -8,7 +8,7 @@ require ( github.com/alecthomas/kong v0.8.0 github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87 github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072 - github.com/bluenviron/gortsplib/v3 v3.9.0 + github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230730204034-8b8b52e689d9 github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda github.com/fsnotify/fsnotify v1.6.0 github.com/gin-gonic/gin v1.9.1 diff --git a/go.sum b/go.sum index 2601f663..1db24c58 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87 h1:SCAqalLhg github.com/asticode/go-astits v1.11.1-0.20230727094110-0df190a2dd87/go.mod h1:QSHmknZ51pf6KJdHKZHJTLlMegIrhega3LPWz3ND/iI= github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072 h1:pAbC7frXsTMxP7Ck3E50hl7oFeSeD2dgc2lWjmHXztQ= github.com/bluenviron/gohlslib v0.3.1-0.20230730162911-eb9f86511072/go.mod h1:rK4b161qErs82QqvBEl84vpi2xhdZBUT0yubXuytZ7E= -github.com/bluenviron/gortsplib/v3 v3.9.0 h1:aAHV6MhsDtgBF6yKaNBBCdvtSpLB8ne4kyUfLQlN7nM= -github.com/bluenviron/gortsplib/v3 v3.9.0/go.mod h1:5h3Zu7jkzwDknYrf+89q2saab//oioKgM9mgvBEX3pg= +github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230730204034-8b8b52e689d9 h1:QBdUlT/taEG0b8dxguJ6GYT7r6vJFRhvwlhs1LGWYlQ= +github.com/bluenviron/gortsplib/v3 v3.9.1-0.20230730204034-8b8b52e689d9/go.mod h1:vBmCYjtox2pXWSvU+r9ROpEbwSOhh5lVWd+t9Sj8glc= github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda h1:+ungCWRNDjsy/CVL1l/UjAj4vYL4+NIJQoJJWbR3Xw8= github.com/bluenviron/mediacommon v0.7.1-0.20230730144331-10b74a4f6eda/go.mod h1:tfk0qGPhqnOxVCrElu8ct3LKQn6Cj4Tpu3zbbJBTKj4= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= diff --git a/internal/core/path.go b/internal/core/path.go index b0957bb9..0cc0326a 100644 --- a/internal/core/path.go +++ b/internal/core/path.go @@ -115,7 +115,7 @@ type pathReaderAddReq struct { res chan pathReaderSetupPlayRes } -type pathPublisherAnnounceRes struct { +type pathPublisherAddRes struct { path *path err error } @@ -125,7 +125,7 @@ type pathPublisherAddReq struct { pathName string skipAuth bool credentials authCredentials - res chan pathPublisherAnnounceRes + res chan pathPublisherAddRes } type pathPublisherRecordRes struct { @@ -743,7 +743,7 @@ func (pa *path) handlePublisherRemove(req pathPublisherRemoveReq) { func (pa *path) handlePublisherAdd(req pathPublisherAddReq) { if pa.conf.Source != "publisher" { - req.res <- pathPublisherAnnounceRes{ + req.res <- pathPublisherAddRes{ err: fmt.Errorf("can't publish to path '%s' since 'source' is not 'publisher'", pa.name), } return @@ -751,7 +751,7 @@ func (pa *path) handlePublisherAdd(req pathPublisherAddReq) { if pa.source != nil { if pa.conf.DisablePublisherOverride { - req.res <- pathPublisherAnnounceRes{err: fmt.Errorf("someone is already publishing to path '%s'", pa.name)} + req.res <- pathPublisherAddRes{err: fmt.Errorf("someone is already publishing to path '%s'", pa.name)} return } @@ -762,7 +762,7 @@ func (pa *path) handlePublisherAdd(req pathPublisherAddReq) { pa.source = req.author - req.res <- pathPublisherAnnounceRes{path: pa} + req.res <- pathPublisherAddRes{path: pa} } func (pa *path) handlePublisherStart(req pathPublisherStartReq) { @@ -973,12 +973,12 @@ func (pa *path) publisherRemove(req pathPublisherRemoveReq) { } // publisherAdd is called by a publisher through pathManager. -func (pa *path) publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes { +func (pa *path) publisherAdd(req pathPublisherAddReq) pathPublisherAddRes { select { case pa.chPublisherAdd <- req: return <-req.res case <-pa.ctx.Done(): - return pathPublisherAnnounceRes{err: fmt.Errorf("terminated")} + return pathPublisherAddRes{err: fmt.Errorf("terminated")} } } diff --git a/internal/core/path_manager.go b/internal/core/path_manager.go index e048006f..98829b85 100644 --- a/internal/core/path_manager.go +++ b/internal/core/path_manager.go @@ -289,14 +289,14 @@ outer: case req := <-pm.chPublisherAdd: pathConfName, pathConf, pathMatches, err := getConfForPath(pm.pathConfs, req.pathName) if err != nil { - req.res <- pathPublisherAnnounceRes{err: err} + req.res <- pathPublisherAddRes{err: err} continue } if !req.skipAuth { err = doAuthentication(pm.externalAuthenticationURL, pm.authMethods, req.pathName, pathConf, true, req.credentials) if err != nil { - req.res <- pathPublisherAnnounceRes{err: err} + req.res <- pathPublisherAddRes{err: err} continue } } @@ -306,7 +306,7 @@ outer: pm.createPath(pathConfName, pathConf, req.pathName, pathMatches) } - req.res <- pathPublisherAnnounceRes{path: pm.paths[req.pathName]} + req.res <- pathPublisherAddRes{path: pm.paths[req.pathName]} case s := <-pm.chHLSManagerSet: pm.hlsManager = s @@ -449,8 +449,8 @@ func (pm *pathManager) describe(req pathDescribeReq) pathDescribeRes { } // publisherAnnounce is called by a publisher. -func (pm *pathManager) publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes { - req.res = make(chan pathPublisherAnnounceRes) +func (pm *pathManager) publisherAdd(req pathPublisherAddReq) pathPublisherAddRes { + req.res = make(chan pathPublisherAddRes) select { case pm.chPublisherAdd <- req: res := <-req.res @@ -461,7 +461,7 @@ func (pm *pathManager) publisherAdd(req pathPublisherAddReq) pathPublisherAnnoun return res.path.publisherAdd(req) case <-pm.ctx.Done(): - return pathPublisherAnnounceRes{err: fmt.Errorf("terminated")} + return pathPublisherAddRes{err: fmt.Errorf("terminated")} } } diff --git a/internal/core/rtmp_conn.go b/internal/core/rtmp_conn.go index 2ad03352..410e0758 100644 --- a/internal/core/rtmp_conn.go +++ b/internal/core/rtmp_conn.go @@ -48,7 +48,7 @@ const ( type rtmpConnPathManager interface { readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes - publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes + publisherAdd(req pathPublisherAddReq) pathPublisherAddRes } type rtmpConnParent interface { diff --git a/internal/core/rtsp_conn.go b/internal/core/rtsp_conn.go index bc7e1383..9d11e95b 100644 --- a/internal/core/rtsp_conn.go +++ b/internal/core/rtsp_conn.go @@ -137,7 +137,13 @@ func (c *rtspConn) onDescribe(ctx *gortsplib.ServerHandlerOnDescribeCtx, ctx.Path = ctx.Path[1:] if c.authNonce == "" { - c.authNonce = auth.GenerateNonce() + var err error + c.authNonce, err = auth.GenerateNonce() + if err != nil { + return &base.Response{ + StatusCode: base.StatusInternalServerError, + }, nil, err + } } res := c.pathManager.describe(pathDescribeReq{ diff --git a/internal/core/rtsp_session.go b/internal/core/rtsp_session.go index 5664624f..6bd9345a 100644 --- a/internal/core/rtsp_session.go +++ b/internal/core/rtsp_session.go @@ -21,7 +21,7 @@ import ( ) type rtspSessionPathManager interface { - publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes + publisherAdd(req pathPublisherAddReq) pathPublisherAddRes readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes } @@ -122,7 +122,13 @@ func (s *rtspSession) onAnnounce(c *rtspConn, ctx *gortsplib.ServerHandlerOnAnno ctx.Path = ctx.Path[1:] if c.authNonce == "" { - c.authNonce = auth.GenerateNonce() + var err error + c.authNonce, err = auth.GenerateNonce() + if err != nil { + return &base.Response{ + StatusCode: base.StatusInternalServerError, + }, err + } } res := s.pathManager.publisherAdd(pathPublisherAddReq{ @@ -201,7 +207,13 @@ func (s *rtspSession) onSetup(c *rtspConn, ctx *gortsplib.ServerHandlerOnSetupCt } if c.authNonce == "" { - c.authNonce = auth.GenerateNonce() + var err error + c.authNonce, err = auth.GenerateNonce() + if err != nil { + return &base.Response{ + StatusCode: base.StatusInternalServerError, + }, nil, err + } } res := s.pathManager.readerAdd(pathReaderAddReq{ diff --git a/internal/core/rtsp_source.go b/internal/core/rtsp_source.go index 6d14406f..40569cd0 100644 --- a/internal/core/rtsp_source.go +++ b/internal/core/rtsp_source.go @@ -2,11 +2,6 @@ package core import ( "context" - "crypto/sha256" - "crypto/tls" - "encoding/hex" - "fmt" - "strings" "time" "github.com/bluenviron/gortsplib/v3" @@ -19,37 +14,6 @@ import ( "github.com/bluenviron/mediamtx/internal/logger" ) -type rtspSourceParent interface { - logger.Writer - sourceStaticImplSetReady(req pathSourceStaticSetReadyReq) pathSourceStaticSetReadyRes - sourceStaticImplSetNotReady(req pathSourceStaticSetNotReadyReq) -} - -type rtspSource struct { - readTimeout conf.StringDuration - writeTimeout conf.StringDuration - readBufferCount int - parent rtspSourceParent -} - -func newRTSPSource( - readTimeout conf.StringDuration, - writeTimeout conf.StringDuration, - readBufferCount int, - parent rtspSourceParent, -) *rtspSource { - return &rtspSource{ - readTimeout: readTimeout, - writeTimeout: writeTimeout, - readBufferCount: readBufferCount, - parent: parent, - } -} - -func (s *rtspSource) Log(level logger.Level, format string, args ...interface{}) { - s.parent.Log(level, "[rtsp source] "+format, args...) -} - func createRangeHeader(cnf *conf.PathConf) (*headers.Range, error) { switch cnf.RtspRangeType { case conf.RtspRangeTypeClock: @@ -95,33 +59,44 @@ func createRangeHeader(cnf *conf.PathConf) (*headers.Range, error) { } } +type rtspSourceParent interface { + logger.Writer + sourceStaticImplSetReady(req pathSourceStaticSetReadyReq) pathSourceStaticSetReadyRes + sourceStaticImplSetNotReady(req pathSourceStaticSetNotReadyReq) +} + +type rtspSource struct { + readTimeout conf.StringDuration + writeTimeout conf.StringDuration + readBufferCount int + parent rtspSourceParent +} + +func newRTSPSource( + readTimeout conf.StringDuration, + writeTimeout conf.StringDuration, + readBufferCount int, + parent rtspSourceParent, +) *rtspSource { + return &rtspSource{ + readTimeout: readTimeout, + writeTimeout: writeTimeout, + readBufferCount: readBufferCount, + parent: parent, + } +} + +func (s *rtspSource) Log(level logger.Level, format string, args ...interface{}) { + s.parent.Log(level, "[rtsp source] "+format, args...) +} + // run implements sourceStaticImpl. func (s *rtspSource) run(ctx context.Context, cnf *conf.PathConf, reloadConf chan *conf.PathConf) error { s.Log(logger.Debug, "connecting") - var tlsConfig *tls.Config - if cnf.SourceFingerprint != "" { - tlsConfig = &tls.Config{ - InsecureSkipVerify: true, - VerifyConnection: func(cs tls.ConnectionState) error { - h := sha256.New() - h.Write(cs.PeerCertificates[0].Raw) - hstr := hex.EncodeToString(h.Sum(nil)) - fingerprintLower := strings.ToLower(cnf.SourceFingerprint) - - if hstr != fingerprintLower { - return fmt.Errorf("server fingerprint do not match: expected %s, got %s", - fingerprintLower, hstr) - } - - return nil - }, - } - } - c := &gortsplib.Client{ Transport: cnf.SourceProtocol.Transport, - TLSConfig: tlsConfig, + TLSConfig: tlsConfigForFingerprint(cnf.SourceFingerprint), ReadTimeout: time.Duration(s.readTimeout), WriteTimeout: time.Duration(s.writeTimeout), ReadBufferCount: s.readBufferCount, diff --git a/internal/core/rtsp_source_test.go b/internal/core/rtsp_source_test.go index 0032470c..5ab0b7ed 100644 --- a/internal/core/rtsp_source_test.go +++ b/internal/core/rtsp_source_test.go @@ -43,7 +43,9 @@ func TestRTSPSource(t *testing.T) { t.Run(source, func(t *testing.T) { medi := testMediaH264 stream := gortsplib.NewServerStream(media.Medias{medi}) - nonce := auth.GenerateNonce() + + nonce, err := auth.GenerateNonce() + require.NoError(t, err) s := gortsplib.Server{ Handler: &testServer{ @@ -112,7 +114,7 @@ func TestRTSPSource(t *testing.T) { s.TLSConfig = &tls.Config{Certificates: []tls.Certificate{cert}} } - err := s.Start() + err = s.Start() require.NoError(t, err) defer s.Wait() defer s.Close() @@ -167,7 +169,10 @@ func TestRTSPSource(t *testing.T) { func TestRTSPSourceNoPassword(t *testing.T) { stream := gortsplib.NewServerStream(media.Medias{testMediaH264}) - nonce := auth.GenerateNonce() + + nonce, err := auth.GenerateNonce() + require.NoError(t, err) + done := make(chan struct{}) s := gortsplib.Server{ @@ -201,7 +206,7 @@ func TestRTSPSourceNoPassword(t *testing.T) { }, RTSPAddress: "127.0.0.1:8555", } - err := s.Start() + err = s.Start() require.NoError(t, err) defer s.Wait() defer s.Close() diff --git a/internal/core/webrtc_session.go b/internal/core/webrtc_session.go index b9d4e79d..93592e2b 100644 --- a/internal/core/webrtc_session.go +++ b/internal/core/webrtc_session.go @@ -131,7 +131,7 @@ func gatherIncomingTracks( } type webRTCSessionPathManager interface { - publisherAdd(req pathPublisherAddReq) pathPublisherAnnounceRes + publisherAdd(req pathPublisherAddReq) pathPublisherAddRes readerAdd(req pathReaderAddReq) pathReaderSetupPlayRes }