forked from External/mediamtx
move conf into dedicated folder
This commit is contained in:
parent
a0e053196d
commit
606806777a
8 changed files with 134 additions and 130 deletions
27
client.go
27
client.go
|
|
@ -16,6 +16,7 @@ import (
|
|||
"github.com/aler9/gortsplib/headers"
|
||||
"github.com/aler9/gortsplib/rtcpreceiver"
|
||||
|
||||
"github.com/aler9/rtsp-simple-server/conf"
|
||||
"github.com/aler9/rtsp-simple-server/externalcmd"
|
||||
)
|
||||
|
||||
|
|
@ -27,14 +28,14 @@ const (
|
|||
type clientDescribeReq struct {
|
||||
client *client
|
||||
pathName string
|
||||
pathConf *pathConf
|
||||
pathConf *conf.PathConf
|
||||
}
|
||||
|
||||
type clientAnnounceReq struct {
|
||||
res chan error
|
||||
client *client
|
||||
pathName string
|
||||
pathConf *pathConf
|
||||
pathConf *conf.PathConf
|
||||
trackCount int
|
||||
sdp []byte
|
||||
}
|
||||
|
|
@ -260,7 +261,7 @@ func (c *client) authenticate(ips []interface{}, user string, pass string, req *
|
|||
if c.authHelper == nil || c.authUser != user || c.authPass != pass {
|
||||
c.authUser = user
|
||||
c.authPass = pass
|
||||
c.authHelper = auth.NewServer(user, pass, c.p.conf.authMethodsParsed)
|
||||
c.authHelper = auth.NewServer(user, pass, c.p.conf.AuthMethodsParsed)
|
||||
}
|
||||
|
||||
err := c.authHelper.ValidateHeader(req.Header["Authorization"], req.Method, req.Url)
|
||||
|
|
@ -371,13 +372,13 @@ func (c *client) handleRequest(req *base.Request) error {
|
|||
|
||||
pathName = removeQueryFromPath(pathName)
|
||||
|
||||
pathConf, err := c.p.conf.checkPathNameAndFindConf(pathName)
|
||||
pathConf, err := c.p.conf.CheckPathNameAndFindConf(pathName)
|
||||
if err != nil {
|
||||
c.writeResError(cseq, base.StatusBadRequest, err)
|
||||
return errRunTerminate
|
||||
}
|
||||
|
||||
err = c.authenticate(pathConf.readIpsParsed, pathConf.ReadUser, pathConf.ReadPass, req)
|
||||
err = c.authenticate(pathConf.ReadIpsParsed, pathConf.ReadUser, pathConf.ReadPass, req)
|
||||
if err != nil {
|
||||
if err == errAuthCritical {
|
||||
return errRunTerminate
|
||||
|
|
@ -401,13 +402,13 @@ func (c *client) handleRequest(req *base.Request) error {
|
|||
|
||||
pathName = removeQueryFromPath(pathName)
|
||||
|
||||
pathConf, err := c.p.conf.checkPathNameAndFindConf(pathName)
|
||||
pathConf, err := c.p.conf.CheckPathNameAndFindConf(pathName)
|
||||
if err != nil {
|
||||
c.writeResError(cseq, base.StatusBadRequest, err)
|
||||
return errRunTerminate
|
||||
}
|
||||
|
||||
err = c.authenticate(pathConf.publishIpsParsed, pathConf.PublishUser, pathConf.PublishPass, req)
|
||||
err = c.authenticate(pathConf.PublishIpsParsed, pathConf.PublishUser, pathConf.PublishPass, req)
|
||||
if err != nil {
|
||||
if err == errAuthCritical {
|
||||
return errRunTerminate
|
||||
|
|
@ -483,13 +484,13 @@ func (c *client) handleRequest(req *base.Request) error {
|
|||
return errRunTerminate
|
||||
}
|
||||
|
||||
pathConf, err := c.p.conf.checkPathNameAndFindConf(basePath)
|
||||
pathConf, err := c.p.conf.CheckPathNameAndFindConf(basePath)
|
||||
if err != nil {
|
||||
c.writeResError(cseq, base.StatusBadRequest, err)
|
||||
return errRunTerminate
|
||||
}
|
||||
|
||||
err = c.authenticate(pathConf.readIpsParsed, pathConf.ReadUser, pathConf.ReadPass, req)
|
||||
err = c.authenticate(pathConf.ReadIpsParsed, pathConf.ReadUser, pathConf.ReadPass, req)
|
||||
if err != nil {
|
||||
if err == errAuthCritical {
|
||||
return errRunTerminate
|
||||
|
|
@ -521,7 +522,7 @@ func (c *client) handleRequest(req *base.Request) error {
|
|||
|
||||
// play with UDP
|
||||
if th.Protocol == gortsplib.StreamProtocolUDP {
|
||||
if _, ok := c.p.conf.protocolsParsed[gortsplib.StreamProtocolUDP]; !ok {
|
||||
if _, ok := c.p.conf.ProtocolsParsed[gortsplib.StreamProtocolUDP]; !ok {
|
||||
c.writeResError(cseq, base.StatusUnsupportedTransport, fmt.Errorf("UDP streaming is disabled"))
|
||||
return errRunTerminate
|
||||
}
|
||||
|
|
@ -572,7 +573,7 @@ func (c *client) handleRequest(req *base.Request) error {
|
|||
|
||||
// play with TCP
|
||||
} else {
|
||||
if _, ok := c.p.conf.protocolsParsed[gortsplib.StreamProtocolTCP]; !ok {
|
||||
if _, ok := c.p.conf.ProtocolsParsed[gortsplib.StreamProtocolTCP]; !ok {
|
||||
c.writeResError(cseq, base.StatusUnsupportedTransport, fmt.Errorf("TCP streaming is disabled"))
|
||||
return errRunTerminate
|
||||
}
|
||||
|
|
@ -629,7 +630,7 @@ func (c *client) handleRequest(req *base.Request) error {
|
|||
|
||||
// record with UDP
|
||||
if th.Protocol == gortsplib.StreamProtocolUDP {
|
||||
if _, ok := c.p.conf.protocolsParsed[gortsplib.StreamProtocolUDP]; !ok {
|
||||
if _, ok := c.p.conf.ProtocolsParsed[gortsplib.StreamProtocolUDP]; !ok {
|
||||
c.writeResError(cseq, base.StatusUnsupportedTransport, fmt.Errorf("UDP streaming is disabled"))
|
||||
return errRunTerminate
|
||||
}
|
||||
|
|
@ -677,7 +678,7 @@ func (c *client) handleRequest(req *base.Request) error {
|
|||
|
||||
// record with TCP
|
||||
} else {
|
||||
if _, ok := c.p.conf.protocolsParsed[gortsplib.StreamProtocolTCP]; !ok {
|
||||
if _, ok := c.p.conf.ProtocolsParsed[gortsplib.StreamProtocolTCP]; !ok {
|
||||
c.writeResError(cseq, base.StatusUnsupportedTransport, fmt.Errorf("TCP streaming is disabled"))
|
||||
return errRunTerminate
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
package main
|
||||
package conf
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"os"
|
||||
"regexp"
|
||||
|
|
@ -17,12 +17,58 @@ import (
|
|||
"github.com/aler9/rtsp-simple-server/loghandler"
|
||||
)
|
||||
|
||||
type pathConf struct {
|
||||
regexp *regexp.Regexp
|
||||
func parseIpCidrList(in []string) ([]interface{}, error) {
|
||||
if len(in) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var ret []interface{}
|
||||
for _, t := range in {
|
||||
_, ipnet, err := net.ParseCIDR(t)
|
||||
if err == nil {
|
||||
ret = append(ret, ipnet)
|
||||
continue
|
||||
}
|
||||
|
||||
ip := net.ParseIP(t)
|
||||
if ip != nil {
|
||||
ret = append(ret, ip)
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to parse ip/network '%s'", t)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
var rePathName = regexp.MustCompile("^[0-9a-zA-Z_\\-/]+$")
|
||||
|
||||
func checkPathName(name string) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("cannot be empty")
|
||||
}
|
||||
|
||||
if name[0] == '/' {
|
||||
return fmt.Errorf("can't begin with a slash")
|
||||
}
|
||||
|
||||
if name[len(name)-1] == '/' {
|
||||
return fmt.Errorf("can't end with a slash")
|
||||
}
|
||||
|
||||
if !rePathName.MatchString(name) {
|
||||
return fmt.Errorf("can contain only alfanumeric characters, underscore, minus or slash")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type PathConf struct {
|
||||
Regexp *regexp.Regexp
|
||||
Source string `yaml:"source"`
|
||||
sourceUrl *url.URL ``
|
||||
SourceUrl *url.URL `yaml:"-"`
|
||||
SourceProtocol string `yaml:"sourceProtocol"`
|
||||
sourceProtocolParsed gortsplib.StreamProtocol ``
|
||||
SourceProtocolParsed gortsplib.StreamProtocol `yaml:"-"`
|
||||
SourceOnDemand bool `yaml:"sourceOnDemand"`
|
||||
RunOnInit string `yaml:"runOnInit"`
|
||||
RunOnDemand string `yaml:"runOnDemand"`
|
||||
|
|
@ -31,16 +77,16 @@ type pathConf struct {
|
|||
PublishUser string `yaml:"publishUser"`
|
||||
PublishPass string `yaml:"publishPass"`
|
||||
PublishIps []string `yaml:"publishIps"`
|
||||
publishIpsParsed []interface{} ``
|
||||
PublishIpsParsed []interface{} `yaml:"-"`
|
||||
ReadUser string `yaml:"readUser"`
|
||||
ReadPass string `yaml:"readPass"`
|
||||
ReadIps []string `yaml:"readIps"`
|
||||
readIpsParsed []interface{} ``
|
||||
ReadIpsParsed []interface{} `yaml:"-"`
|
||||
}
|
||||
|
||||
type conf struct {
|
||||
type Conf struct {
|
||||
Protocols []string `yaml:"protocols"`
|
||||
protocolsParsed map[gortsplib.StreamProtocol]struct{} ``
|
||||
ProtocolsParsed map[gortsplib.StreamProtocol]struct{} `yaml:"-"`
|
||||
RtspPort int `yaml:"rtspPort"`
|
||||
RtpPort int `yaml:"rtpPort"`
|
||||
RtcpPort int `yaml:"rtcpPort"`
|
||||
|
|
@ -48,19 +94,19 @@ type conf struct {
|
|||
ReadTimeout time.Duration `yaml:"readTimeout"`
|
||||
WriteTimeout time.Duration `yaml:"writeTimeout"`
|
||||
AuthMethods []string `yaml:"authMethods"`
|
||||
authMethodsParsed []headers.AuthMethod ``
|
||||
AuthMethodsParsed []headers.AuthMethod `yaml:"-"`
|
||||
Metrics bool `yaml:"metrics"`
|
||||
Pprof bool `yaml:"pprof"`
|
||||
LogDestinations []string `yaml:"logDestinations"`
|
||||
logDestinationsParsed map[loghandler.Destination]struct{} ``
|
||||
LogDestinationsParsed map[loghandler.Destination]struct{} `yaml:"-"`
|
||||
LogFile string `yaml:"logFile"`
|
||||
Paths map[string]*pathConf `yaml:"paths"`
|
||||
Paths map[string]*PathConf `yaml:"paths"`
|
||||
}
|
||||
|
||||
func loadConf(fpath string) (*conf, error) {
|
||||
conf := &conf{}
|
||||
func Load(fpath string) (*Conf, error) {
|
||||
conf := &Conf{}
|
||||
|
||||
// read from file or stdin
|
||||
// read from file
|
||||
err := func() error {
|
||||
// rtsp-simple-server.yml is optional
|
||||
if fpath == "rtsp-simple-server.yml" {
|
||||
|
|
@ -95,20 +141,20 @@ func loadConf(fpath string) (*conf, error) {
|
|||
if len(conf.Protocols) == 0 {
|
||||
conf.Protocols = []string{"udp", "tcp"}
|
||||
}
|
||||
conf.protocolsParsed = make(map[gortsplib.StreamProtocol]struct{})
|
||||
conf.ProtocolsParsed = make(map[gortsplib.StreamProtocol]struct{})
|
||||
for _, proto := range conf.Protocols {
|
||||
switch proto {
|
||||
case "udp":
|
||||
conf.protocolsParsed[gortsplib.StreamProtocolUDP] = struct{}{}
|
||||
conf.ProtocolsParsed[gortsplib.StreamProtocolUDP] = struct{}{}
|
||||
|
||||
case "tcp":
|
||||
conf.protocolsParsed[gortsplib.StreamProtocolTCP] = struct{}{}
|
||||
conf.ProtocolsParsed[gortsplib.StreamProtocolTCP] = struct{}{}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported protocol: %s", proto)
|
||||
}
|
||||
}
|
||||
if len(conf.protocolsParsed) == 0 {
|
||||
if len(conf.ProtocolsParsed) == 0 {
|
||||
return nil, fmt.Errorf("no protocols provided")
|
||||
}
|
||||
|
||||
|
|
@ -141,10 +187,10 @@ func loadConf(fpath string) (*conf, error) {
|
|||
for _, method := range conf.AuthMethods {
|
||||
switch method {
|
||||
case "basic":
|
||||
conf.authMethodsParsed = append(conf.authMethodsParsed, headers.AuthBasic)
|
||||
conf.AuthMethodsParsed = append(conf.AuthMethodsParsed, headers.AuthBasic)
|
||||
|
||||
case "digest":
|
||||
conf.authMethodsParsed = append(conf.authMethodsParsed, headers.AuthDigest)
|
||||
conf.AuthMethodsParsed = append(conf.AuthMethodsParsed, headers.AuthDigest)
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported authentication method: %s", method)
|
||||
|
|
@ -154,17 +200,17 @@ func loadConf(fpath string) (*conf, error) {
|
|||
if len(conf.LogDestinations) == 0 {
|
||||
conf.LogDestinations = []string{"stdout"}
|
||||
}
|
||||
conf.logDestinationsParsed = make(map[loghandler.Destination]struct{})
|
||||
conf.LogDestinationsParsed = make(map[loghandler.Destination]struct{})
|
||||
for _, dest := range conf.LogDestinations {
|
||||
switch dest {
|
||||
case "stdout":
|
||||
conf.logDestinationsParsed[loghandler.DestinationStdout] = struct{}{}
|
||||
conf.LogDestinationsParsed[loghandler.DestinationStdout] = struct{}{}
|
||||
|
||||
case "file":
|
||||
conf.logDestinationsParsed[loghandler.DestinationFile] = struct{}{}
|
||||
conf.LogDestinationsParsed[loghandler.DestinationFile] = struct{}{}
|
||||
|
||||
case "syslog":
|
||||
conf.logDestinationsParsed[loghandler.DestinationSyslog] = struct{}{}
|
||||
conf.LogDestinationsParsed[loghandler.DestinationSyslog] = struct{}{}
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported log destination: %s", dest)
|
||||
|
|
@ -175,7 +221,7 @@ func loadConf(fpath string) (*conf, error) {
|
|||
}
|
||||
|
||||
if len(conf.Paths) == 0 {
|
||||
conf.Paths = map[string]*pathConf{
|
||||
conf.Paths = map[string]*PathConf{
|
||||
"all": {},
|
||||
}
|
||||
}
|
||||
|
|
@ -188,7 +234,7 @@ func loadConf(fpath string) (*conf, error) {
|
|||
|
||||
for name, pconf := range conf.Paths {
|
||||
if pconf == nil {
|
||||
conf.Paths[name] = &pathConf{}
|
||||
conf.Paths[name] = &PathConf{}
|
||||
pconf = conf.Paths[name]
|
||||
}
|
||||
|
||||
|
|
@ -209,7 +255,7 @@ func loadConf(fpath string) (*conf, error) {
|
|||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid regular expression: %s", name[1:])
|
||||
}
|
||||
pconf.regexp = pathRegexp
|
||||
pconf.Regexp = pathRegexp
|
||||
}
|
||||
|
||||
if pconf.Source == "" {
|
||||
|
|
@ -217,20 +263,20 @@ func loadConf(fpath string) (*conf, error) {
|
|||
}
|
||||
|
||||
if strings.HasPrefix(pconf.Source, "rtsp://") {
|
||||
if pconf.regexp != nil {
|
||||
if pconf.Regexp != nil {
|
||||
return nil, fmt.Errorf("a path with a regular expression (or path 'all') cannot have a RTSP source; use another path")
|
||||
}
|
||||
|
||||
pconf.sourceUrl, err = url.Parse(pconf.Source)
|
||||
pconf.SourceUrl, err = url.Parse(pconf.Source)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("'%s' is not a valid url", pconf.Source)
|
||||
}
|
||||
if pconf.sourceUrl.Port() == "" {
|
||||
pconf.sourceUrl.Host += ":554"
|
||||
if pconf.SourceUrl.Port() == "" {
|
||||
pconf.SourceUrl.Host += ":554"
|
||||
}
|
||||
if pconf.sourceUrl.User != nil {
|
||||
pass, _ := pconf.sourceUrl.User.Password()
|
||||
user := pconf.sourceUrl.User.Username()
|
||||
if pconf.SourceUrl.User != nil {
|
||||
pass, _ := pconf.SourceUrl.User.Password()
|
||||
user := pconf.SourceUrl.User.Username()
|
||||
if user != "" && pass == "" ||
|
||||
user == "" && pass != "" {
|
||||
fmt.Errorf("username and password must be both provided")
|
||||
|
|
@ -242,26 +288,26 @@ func loadConf(fpath string) (*conf, error) {
|
|||
}
|
||||
switch pconf.SourceProtocol {
|
||||
case "udp":
|
||||
pconf.sourceProtocolParsed = gortsplib.StreamProtocolUDP
|
||||
pconf.SourceProtocolParsed = gortsplib.StreamProtocolUDP
|
||||
|
||||
case "tcp":
|
||||
pconf.sourceProtocolParsed = gortsplib.StreamProtocolTCP
|
||||
pconf.SourceProtocolParsed = gortsplib.StreamProtocolTCP
|
||||
|
||||
default:
|
||||
return nil, fmt.Errorf("unsupported protocol '%s'", pconf.SourceProtocol)
|
||||
}
|
||||
|
||||
} else if strings.HasPrefix(pconf.Source, "rtmp://") {
|
||||
if pconf.regexp != nil {
|
||||
if pconf.Regexp != nil {
|
||||
return nil, fmt.Errorf("a path with a regular expression (or path 'all') cannot have a RTMP source; use another path")
|
||||
}
|
||||
|
||||
pconf.sourceUrl, err = url.Parse(pconf.Source)
|
||||
pconf.SourceUrl, err = url.Parse(pconf.Source)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("'%s' is not a valid url", pconf.Source)
|
||||
}
|
||||
if pconf.sourceUrl.Port() == "" {
|
||||
pconf.sourceUrl.Host += ":1935"
|
||||
if pconf.SourceUrl.Port() == "" {
|
||||
pconf.SourceUrl.Host += ":1935"
|
||||
}
|
||||
|
||||
} else if pconf.Source == "record" {
|
||||
|
|
@ -280,7 +326,7 @@ func loadConf(fpath string) (*conf, error) {
|
|||
return nil, fmt.Errorf("publish password must be alphanumeric")
|
||||
}
|
||||
}
|
||||
pconf.publishIpsParsed, err = parseIpCidrList(pconf.PublishIps)
|
||||
pconf.PublishIpsParsed, err = parseIpCidrList(pconf.PublishIps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -301,12 +347,12 @@ func loadConf(fpath string) (*conf, error) {
|
|||
if pconf.ReadUser != "" && pconf.ReadPass == "" || pconf.ReadUser == "" && pconf.ReadPass != "" {
|
||||
return nil, fmt.Errorf("read username and password must be both filled")
|
||||
}
|
||||
pconf.readIpsParsed, err = parseIpCidrList(pconf.ReadIps)
|
||||
pconf.ReadIpsParsed, err = parseIpCidrList(pconf.ReadIps)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if pconf.regexp != nil && pconf.RunOnInit != "" {
|
||||
if pconf.Regexp != nil && pconf.RunOnInit != "" {
|
||||
return nil, fmt.Errorf("a path with a regular expression does not support option 'runOnInit'; use another path")
|
||||
}
|
||||
}
|
||||
|
|
@ -314,7 +360,7 @@ func loadConf(fpath string) (*conf, error) {
|
|||
return conf, nil
|
||||
}
|
||||
|
||||
func (conf *conf) checkPathNameAndFindConf(name string) (*pathConf, error) {
|
||||
func (conf *Conf) CheckPathNameAndFindConf(name string) (*PathConf, error) {
|
||||
err := checkPathName(name)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid path name: %s (%s)", err, name)
|
||||
|
|
@ -327,7 +373,7 @@ func (conf *conf) checkPathNameAndFindConf(name string) (*pathConf, error) {
|
|||
|
||||
// regular expression path
|
||||
for _, pconf := range conf.Paths {
|
||||
if pconf.regexp != nil && pconf.regexp.MatchString(name) {
|
||||
if pconf.Regexp != nil && pconf.Regexp.MatchString(name) {
|
||||
return pconf, nil
|
||||
}
|
||||
}
|
||||
|
|
@ -94,14 +94,14 @@ func process(env map[string]string, envKey string, rv reflect.Value) error {
|
|||
case reflect.Struct:
|
||||
flen := rt.NumField()
|
||||
for i := 0; i < flen; i++ {
|
||||
fieldName := rt.Field(i).Name
|
||||
f := rt.Field(i)
|
||||
|
||||
// process only public fields
|
||||
if fieldName[0] < 'A' || fieldName[0] > 'Z' {
|
||||
if f.Tag.Get("yaml") == "-" {
|
||||
continue
|
||||
}
|
||||
|
||||
fieldEnvKey := envKey + "_" + strings.ToUpper(fieldName)
|
||||
fieldEnvKey := envKey + "_" + strings.ToUpper(f.Name)
|
||||
err := process(env, fieldEnvKey, rv.Field(i))
|
||||
if err != nil {
|
||||
return err
|
||||
|
|
|
|||
11
main.go
11
main.go
|
|
@ -12,6 +12,7 @@ import (
|
|||
"github.com/aler9/gortsplib"
|
||||
"gopkg.in/alecthomas/kingpin.v2"
|
||||
|
||||
"github.com/aler9/rtsp-simple-server/conf"
|
||||
"github.com/aler9/rtsp-simple-server/loghandler"
|
||||
)
|
||||
|
||||
|
|
@ -22,7 +23,7 @@ const (
|
|||
)
|
||||
|
||||
type program struct {
|
||||
conf *conf
|
||||
conf *conf.Conf
|
||||
logHandler *loghandler.LogHandler
|
||||
metrics *metrics
|
||||
pprof *pprof
|
||||
|
|
@ -72,12 +73,12 @@ func newProgram(args []string, stdin io.Reader) (*program, error) {
|
|||
os.Exit(0)
|
||||
}
|
||||
|
||||
conf, err := loadConf(*argConfPath)
|
||||
conf, err := conf.Load(*argConfPath)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
logHandler, err := loghandler.New(conf.logDestinationsParsed, conf.LogFile)
|
||||
logHandler, err := loghandler.New(conf.LogDestinationsParsed, conf.LogFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -149,12 +150,12 @@ func newProgram(args []string, stdin io.Reader) (*program, error) {
|
|||
}
|
||||
|
||||
for name, pathConf := range conf.Paths {
|
||||
if pathConf.regexp == nil {
|
||||
if pathConf.Regexp == nil {
|
||||
p.paths[name] = newPath(p, name, pathConf)
|
||||
}
|
||||
}
|
||||
|
||||
if _, ok := conf.protocolsParsed[gortsplib.StreamProtocolUDP]; ok {
|
||||
if _, ok := conf.ProtocolsParsed[gortsplib.StreamProtocolUDP]; ok {
|
||||
p.serverUdpRtp, err = newServerUDP(p, conf.RtpPort, gortsplib.StreamTypeRtp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
|
|
|||
10
main_test.go
10
main_test.go
|
|
@ -12,6 +12,8 @@ import (
|
|||
|
||||
"github.com/aler9/gortsplib"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/aler9/rtsp-simple-server/conf"
|
||||
)
|
||||
|
||||
var ownDockerIp = func() string {
|
||||
|
|
@ -163,20 +165,20 @@ func TestEnvironment(t *testing.T) {
|
|||
|
||||
pa, ok := p.conf.Paths["test2"]
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, &pathConf{
|
||||
require.Equal(t, &conf.PathConf{
|
||||
Source: "record",
|
||||
}, pa)
|
||||
|
||||
pa, ok = p.conf.Paths["test"]
|
||||
require.Equal(t, true, ok)
|
||||
require.Equal(t, &pathConf{
|
||||
require.Equal(t, &conf.PathConf{
|
||||
Source: "rtsp://testing",
|
||||
sourceUrl: func() *url.URL {
|
||||
SourceUrl: func() *url.URL {
|
||||
u, _ := url.Parse("rtsp://testing:554")
|
||||
return u
|
||||
}(),
|
||||
SourceProtocol: "tcp",
|
||||
sourceProtocolParsed: gortsplib.StreamProtocolTCP,
|
||||
SourceProtocolParsed: gortsplib.StreamProtocolTCP,
|
||||
}, pa)
|
||||
}
|
||||
|
||||
|
|
|
|||
7
path.go
7
path.go
|
|
@ -6,6 +6,7 @@ import (
|
|||
"sync/atomic"
|
||||
"time"
|
||||
|
||||
"github.com/aler9/rtsp-simple-server/conf"
|
||||
"github.com/aler9/rtsp-simple-server/externalcmd"
|
||||
)
|
||||
|
||||
|
|
@ -23,7 +24,7 @@ type source interface {
|
|||
type path struct {
|
||||
p *program
|
||||
name string
|
||||
conf *pathConf
|
||||
conf *conf.PathConf
|
||||
source source
|
||||
sourceReady bool
|
||||
sourceTrackCount int
|
||||
|
|
@ -34,7 +35,7 @@ type path struct {
|
|||
onDemandCmd *externalcmd.ExternalCmd
|
||||
}
|
||||
|
||||
func newPath(p *program, name string, conf *pathConf) *path {
|
||||
func newPath(p *program, name string, conf *conf.PathConf) *path {
|
||||
pa := &path{
|
||||
p: p,
|
||||
name: name,
|
||||
|
|
@ -189,7 +190,7 @@ func (pa *path) onCheck() {
|
|||
}
|
||||
|
||||
// remove regular expression paths
|
||||
if pa.conf.regexp != nil &&
|
||||
if pa.conf.Regexp != nil &&
|
||||
pa.source == nil &&
|
||||
!pa.hasClients() {
|
||||
pa.onClose(false)
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ func (s *sourceRtsp) runInnerInner() bool {
|
|||
go func() {
|
||||
defer close(dialDone)
|
||||
conn, err = gortsplib.NewConnClient(gortsplib.ConnClientConf{
|
||||
Host: s.path.conf.sourceUrl.Host,
|
||||
Host: s.path.conf.SourceUrl.Host,
|
||||
ReadTimeout: s.p.conf.ReadTimeout,
|
||||
WriteTimeout: s.p.conf.WriteTimeout,
|
||||
ReadBufferCount: 2,
|
||||
|
|
@ -146,14 +146,14 @@ func (s *sourceRtsp) runInnerInner() bool {
|
|||
return true
|
||||
}
|
||||
|
||||
_, err = conn.Options(s.path.conf.sourceUrl)
|
||||
_, err = conn.Options(s.path.conf.SourceUrl)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
s.path.log("rtsp source ERR: %s", err)
|
||||
return true
|
||||
}
|
||||
|
||||
tracks, _, err := conn.Describe(s.path.conf.sourceUrl)
|
||||
tracks, _, err := conn.Describe(s.path.conf.SourceUrl)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
s.path.log("rtsp source ERR: %s", err)
|
||||
|
|
@ -165,7 +165,7 @@ func (s *sourceRtsp) runInnerInner() bool {
|
|||
s.path.sourceTrackCount = len(tracks)
|
||||
s.tracks = tracks
|
||||
|
||||
if s.path.conf.sourceProtocolParsed == gortsplib.StreamProtocolUDP {
|
||||
if s.path.conf.SourceProtocolParsed == gortsplib.StreamProtocolUDP {
|
||||
return s.runUDP(conn)
|
||||
} else {
|
||||
return s.runTCP(conn)
|
||||
|
|
@ -174,7 +174,7 @@ func (s *sourceRtsp) runInnerInner() bool {
|
|||
|
||||
func (s *sourceRtsp) runUDP(conn *gortsplib.ConnClient) bool {
|
||||
for _, track := range s.tracks {
|
||||
_, err := conn.SetupUDP(s.path.conf.sourceUrl, gortsplib.TransportModePlay, track, 0, 0)
|
||||
_, err := conn.SetupUDP(s.path.conf.SourceUrl, gortsplib.TransportModePlay, track, 0, 0)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
s.path.log("rtsp source ERR: %s", err)
|
||||
|
|
@ -182,7 +182,7 @@ func (s *sourceRtsp) runUDP(conn *gortsplib.ConnClient) bool {
|
|||
}
|
||||
}
|
||||
|
||||
_, err := conn.Play(s.path.conf.sourceUrl)
|
||||
_, err := conn.Play(s.path.conf.SourceUrl)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
s.path.log("rtsp source ERR: %s", err)
|
||||
|
|
@ -264,7 +264,7 @@ outer:
|
|||
|
||||
func (s *sourceRtsp) runTCP(conn *gortsplib.ConnClient) bool {
|
||||
for _, track := range s.tracks {
|
||||
_, err := conn.SetupTCP(s.path.conf.sourceUrl, gortsplib.TransportModePlay, track)
|
||||
_, err := conn.SetupTCP(s.path.conf.SourceUrl, gortsplib.TransportModePlay, track)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
s.path.log("rtsp source ERR: %s", err)
|
||||
|
|
@ -272,7 +272,7 @@ func (s *sourceRtsp) runTCP(conn *gortsplib.ConnClient) bool {
|
|||
}
|
||||
}
|
||||
|
||||
_, err := conn.Play(s.path.conf.sourceUrl)
|
||||
_, err := conn.Play(s.path.conf.SourceUrl)
|
||||
if err != nil {
|
||||
conn.Close()
|
||||
s.path.log("rtsp source ERR: %s", err)
|
||||
|
|
|
|||
47
utils.go
47
utils.go
|
|
@ -3,7 +3,6 @@ package main
|
|||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"regexp"
|
||||
"strings"
|
||||
"sync"
|
||||
|
||||
|
|
@ -11,30 +10,6 @@ import (
|
|||
"github.com/aler9/gortsplib/base"
|
||||
)
|
||||
|
||||
func parseIpCidrList(in []string) ([]interface{}, error) {
|
||||
if len(in) == 0 {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var ret []interface{}
|
||||
for _, t := range in {
|
||||
_, ipnet, err := net.ParseCIDR(t)
|
||||
if err == nil {
|
||||
ret = append(ret, ipnet)
|
||||
continue
|
||||
}
|
||||
|
||||
ip := net.ParseIP(t)
|
||||
if ip != nil {
|
||||
ret = append(ret, ip)
|
||||
continue
|
||||
}
|
||||
|
||||
return nil, fmt.Errorf("unable to parse ip/network '%s'", t)
|
||||
}
|
||||
return ret, nil
|
||||
}
|
||||
|
||||
func ipEqualOrInRange(ip net.IP, ips []interface{}) bool {
|
||||
for _, item := range ips {
|
||||
switch titem := item.(type) {
|
||||
|
|
@ -88,28 +63,6 @@ func removeQueryFromPath(path string) string {
|
|||
return path
|
||||
}
|
||||
|
||||
var rePathName = regexp.MustCompile("^[0-9a-zA-Z_\\-/]+$")
|
||||
|
||||
func checkPathName(name string) error {
|
||||
if name == "" {
|
||||
return fmt.Errorf("cannot be empty")
|
||||
}
|
||||
|
||||
if name[0] == '/' {
|
||||
return fmt.Errorf("can't begin with a slash")
|
||||
}
|
||||
|
||||
if name[len(name)-1] == '/' {
|
||||
return fmt.Errorf("can't end with a slash")
|
||||
}
|
||||
|
||||
if !rePathName.MatchString(name) {
|
||||
return fmt.Errorf("can contain only alfanumeric characters, underscore, minus or slash")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type udpPublisherAddr struct {
|
||||
ip [net.IPv6len]byte // use a fixed-size array to enable the equality operator
|
||||
port int
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue