Reply with NetStream.Play.Failed or NetStream.Publish.Unauthorized when a client is not authorized to play or publish. This makes clients like OBS to stop recreating the connection in case of authentication failures.
144 lines
3.1 KiB
Go
144 lines
3.1 KiB
Go
package rtmp_test
|
|
|
|
import (
|
|
"context"
|
|
"crypto/tls"
|
|
"net"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/bluenviron/gortmplib"
|
|
"github.com/bluenviron/gortmplib/pkg/codecs"
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/bluenviron/mediamtx/internal/conf"
|
|
"github.com/bluenviron/mediamtx/internal/defs"
|
|
"github.com/bluenviron/mediamtx/internal/staticsources/rtmp"
|
|
"github.com/bluenviron/mediamtx/internal/test"
|
|
)
|
|
|
|
func TestSource(t *testing.T) {
|
|
for _, encryption := range []string{
|
|
"plain",
|
|
"tls",
|
|
} {
|
|
for _, auth := range []string{
|
|
"no auth",
|
|
"auth",
|
|
} {
|
|
t.Run(encryption+"_"+auth, func(t *testing.T) {
|
|
var ln net.Listener
|
|
|
|
if encryption == "plain" {
|
|
var err error
|
|
ln, err = net.Listen("tcp", "127.0.0.1:1935")
|
|
require.NoError(t, err)
|
|
} else {
|
|
serverCertFpath := test.CreateTempFile(t, test.TLSCertPub)
|
|
serverKeyFpath := test.CreateTempFile(t, test.TLSCertKey)
|
|
|
|
var cert tls.Certificate
|
|
cert, err := tls.LoadX509KeyPair(serverCertFpath, serverKeyFpath)
|
|
require.NoError(t, err)
|
|
|
|
ln, err = tls.Listen("tcp", "127.0.0.1:1936", &tls.Config{Certificates: []tls.Certificate{cert}})
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
defer ln.Close()
|
|
|
|
var source string
|
|
|
|
if encryption == "plain" {
|
|
source = "rtmp://"
|
|
} else {
|
|
source = "rtmps://"
|
|
}
|
|
|
|
if auth == "auth" {
|
|
source += "myuser:mypass@"
|
|
}
|
|
|
|
source += "localhost/teststream"
|
|
|
|
p := &test.StaticSourceParent{}
|
|
p.Initialize()
|
|
defer p.Close()
|
|
|
|
so := &rtmp.Source{
|
|
ReadTimeout: conf.Duration(10 * time.Second),
|
|
WriteTimeout: conf.Duration(10 * time.Second),
|
|
Parent: p,
|
|
}
|
|
|
|
done := make(chan struct{})
|
|
defer func() { <-done }()
|
|
|
|
ctx, ctxCancel := context.WithCancel(context.Background())
|
|
defer ctxCancel()
|
|
|
|
reloadConf := make(chan *conf.Path)
|
|
|
|
go func() {
|
|
so.Run(defs.StaticSourceRunParams{ //nolint:errcheck
|
|
Context: ctx,
|
|
ResolvedSource: source,
|
|
Conf: &conf.Path{
|
|
SourceFingerprint: "33949E05FFFB5FF3E8AA16F8213A6251B4D9363804BA53233C4DA9A46D6F2739",
|
|
},
|
|
ReloadConf: reloadConf,
|
|
})
|
|
close(done)
|
|
}()
|
|
|
|
for {
|
|
nconn, err := ln.Accept()
|
|
require.NoError(t, err)
|
|
defer nconn.Close()
|
|
|
|
conn := &gortmplib.ServerConn{
|
|
RW: nconn,
|
|
}
|
|
err = conn.Initialize()
|
|
require.NoError(t, err)
|
|
|
|
if auth == "auth" {
|
|
err = conn.AcceptConnIfCredentialsMatch("myuser", "mypass")
|
|
if err != nil {
|
|
continue
|
|
}
|
|
} else {
|
|
err = conn.AcceptConn()
|
|
require.NoError(t, err)
|
|
}
|
|
|
|
w := &gortmplib.Writer{
|
|
Conn: conn,
|
|
Tracks: []*gortmplib.Track{
|
|
{Codec: &codecs.H264{
|
|
SPS: test.FormatH264.SPS,
|
|
PPS: test.FormatH264.PPS,
|
|
}},
|
|
{Codec: &codecs.MPEG4Audio{
|
|
Config: test.FormatMPEG4Audio.Config,
|
|
}},
|
|
},
|
|
}
|
|
err = w.Initialize()
|
|
require.NoError(t, err)
|
|
|
|
err = w.WriteMPEG4Audio(w.Tracks[1], 2*time.Second, []byte{5, 2, 3, 4})
|
|
require.NoError(t, err)
|
|
|
|
break
|
|
}
|
|
|
|
<-p.Unit
|
|
|
|
// the source must be listening on ReloadConf
|
|
reloadConf <- nil
|
|
})
|
|
}
|
|
}
|
|
}
|