mirror of
https://github.com/aler9/gortsplib
synced 2025-10-05 15:16:51 +08:00
export most server errors
This commit is contained in:
@@ -524,7 +524,7 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track,
|
|||||||
th.ClientPorts = &[2]int{rtpPort, rtcpPort}
|
th.ClientPorts = &[2]int{rtpPort, rtcpPort}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
th.InterleavedIds = &[2]int{(track.ID * 2), (track.ID * 2) + 1}
|
th.InterleavedIDs = &[2]int{(track.ID * 2), (track.ID * 2) + 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
trackURL, err := track.URL()
|
trackURL, err := track.URL()
|
||||||
@@ -605,11 +605,11 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if thRes.InterleavedIds == nil ||
|
} else if thRes.InterleavedIDs == nil ||
|
||||||
thRes.InterleavedIds[0] != th.InterleavedIds[0] ||
|
thRes.InterleavedIDs[0] != th.InterleavedIDs[0] ||
|
||||||
thRes.InterleavedIds[1] != th.InterleavedIds[1] {
|
thRes.InterleavedIDs[1] != th.InterleavedIDs[1] {
|
||||||
return nil, fmt.Errorf("transport header does not have interleaved ids %v (%s)",
|
return nil, fmt.Errorf("transport header does not have interleaved ids %v (%s)",
|
||||||
*th.InterleavedIds, res.Header["Transport"])
|
*th.InterleavedIDs, res.Header["Transport"])
|
||||||
}
|
}
|
||||||
|
|
||||||
clockRate, _ := track.ClockRate()
|
clockRate, _ := track.ClockRate()
|
||||||
|
@@ -80,7 +80,7 @@ func TestClientConnPublishSerial(t *testing.T) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
th.Protocol = StreamProtocolTCP
|
th.Protocol = StreamProtocolTCP
|
||||||
th.InterleavedIds = inTH.InterleavedIds
|
th.InterleavedIDs = inTH.InterleavedIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Response{
|
err = base.Response{
|
||||||
@@ -211,7 +211,7 @@ func TestClientConnPublishParallel(t *testing.T) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
th.Protocol = StreamProtocolTCP
|
th.Protocol = StreamProtocolTCP
|
||||||
th.InterleavedIds = inTH.InterleavedIds
|
th.InterleavedIDs = inTH.InterleavedIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Response{
|
err = base.Response{
|
||||||
@@ -354,7 +354,7 @@ func TestClientConnPublishPauseSerial(t *testing.T) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
th.Protocol = StreamProtocolTCP
|
th.Protocol = StreamProtocolTCP
|
||||||
th.InterleavedIds = inTH.InterleavedIds
|
th.InterleavedIDs = inTH.InterleavedIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Response{
|
err = base.Response{
|
||||||
@@ -514,7 +514,7 @@ func TestClientConnPublishPauseParallel(t *testing.T) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
th.Protocol = StreamProtocolTCP
|
th.Protocol = StreamProtocolTCP
|
||||||
th.InterleavedIds = inTH.InterleavedIds
|
th.InterleavedIDs = inTH.InterleavedIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Response{
|
err = base.Response{
|
||||||
|
@@ -134,7 +134,7 @@ func TestClientConnRead(t *testing.T) {
|
|||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
ClientPorts: th.ClientPorts,
|
ClientPorts: th.ClientPorts,
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}.Write(),
|
}.Write(),
|
||||||
},
|
},
|
||||||
}.Write(bconn.Writer)
|
}.Write(bconn.Writer)
|
||||||
@@ -395,7 +395,7 @@ func TestClientConnReadAutomaticProtocol(t *testing.T) {
|
|||||||
v := base.StreamDeliveryUnicast
|
v := base.StreamDeliveryUnicast
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}.Write(),
|
}.Write(),
|
||||||
},
|
},
|
||||||
}.Write(bconn.Writer)
|
}.Write(bconn.Writer)
|
||||||
@@ -690,7 +690,7 @@ func TestClientConnReadPause(t *testing.T) {
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
th.Protocol = StreamProtocolTCP
|
th.Protocol = StreamProtocolTCP
|
||||||
th.InterleavedIds = inTH.InterleavedIds
|
th.InterleavedIDs = inTH.InterleavedIDs
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Response{
|
err = base.Response{
|
||||||
|
@@ -55,7 +55,7 @@ type Transport struct {
|
|||||||
ServerPorts *[2]int
|
ServerPorts *[2]int
|
||||||
|
|
||||||
// (optional) interleaved frame ids
|
// (optional) interleaved frame ids
|
||||||
InterleavedIds *[2]int
|
InterleavedIDs *[2]int
|
||||||
|
|
||||||
// (optional) mode
|
// (optional) mode
|
||||||
Mode *TransportMode
|
Mode *TransportMode
|
||||||
@@ -170,7 +170,7 @@ func (h *Transport) Read(v base.HeaderValue) error {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
h.InterleavedIds = ports
|
h.InterleavedIDs = ports
|
||||||
|
|
||||||
case strings.HasPrefix(t, "mode="):
|
case strings.HasPrefix(t, "mode="):
|
||||||
str := strings.ToLower(t[len("mode="):])
|
str := strings.ToLower(t[len("mode="):])
|
||||||
@@ -227,8 +227,8 @@ func (h Transport) Write() base.HeaderValue {
|
|||||||
rets = append(rets, "server_port="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
rets = append(rets, "server_port="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
if h.InterleavedIds != nil {
|
if h.InterleavedIDs != nil {
|
||||||
ports := *h.InterleavedIds
|
ports := *h.InterleavedIDs
|
||||||
rets = append(rets, "interleaved="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
rets = append(rets, "interleaved="+strconv.FormatInt(int64(ports[0]), 10)+"-"+strconv.FormatInt(int64(ports[1]), 10))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -72,7 +72,7 @@ var casesTransport = []struct {
|
|||||||
base.HeaderValue{`RTP/AVP/TCP;interleaved=0-1`},
|
base.HeaderValue{`RTP/AVP/TCP;interleaved=0-1`},
|
||||||
Transport{
|
Transport{
|
||||||
Protocol: base.StreamProtocolTCP,
|
Protocol: base.StreamProtocolTCP,
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
240
serverconn.go
240
serverconn.go
@@ -3,7 +3,6 @@ package gortsplib
|
|||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
"crypto/tls"
|
"crypto/tls"
|
||||||
"errors"
|
|
||||||
"fmt"
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"strconv"
|
"strconv"
|
||||||
@@ -25,11 +24,166 @@ const (
|
|||||||
serverConnReceiverReportInterval = 10 * time.Second
|
serverConnReceiverReportInterval = 10 * time.Second
|
||||||
)
|
)
|
||||||
|
|
||||||
// server errors.
|
// ErrServerTeardown is returned in case of a teardown request.
|
||||||
var (
|
type ErrServerTeardown struct{}
|
||||||
ErrServerTeardown = errors.New("teardown")
|
|
||||||
errServerCSeqMissing = errors.New("CSeq is missing")
|
// Error implements the error interface.
|
||||||
)
|
func (e ErrServerTeardown) Error() string {
|
||||||
|
return "teardown"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerCSeqMissing is returned in case the CSeq is missing.
|
||||||
|
type ErrServerCSeqMissing struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerCSeqMissing) Error() string {
|
||||||
|
return "CSeq is missing"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerWrongState is returned in case of a wrong client state.
|
||||||
|
type ErrServerWrongState struct {
|
||||||
|
allowedList []ServerConnState
|
||||||
|
state ServerConnState
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerWrongState) Error() string {
|
||||||
|
return fmt.Sprintf("must be in state %v, while is in state %v",
|
||||||
|
e.allowedList, e.state)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerNoPath is returned in case the path can't be retrieved.
|
||||||
|
type ErrServerNoPath struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerNoPath) Error() string {
|
||||||
|
return "RTSP path can't be retrieved"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerContentTypeMissing is returned in case the Content-Type header is missing.
|
||||||
|
type ErrServerContentTypeMissing struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerContentTypeMissing) Error() string {
|
||||||
|
return "Content-Type header is missing"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerContentTypeUnsupported is returned in case the Content-Type header is unsupported.
|
||||||
|
type ErrServerContentTypeUnsupported struct {
|
||||||
|
ct base.HeaderValue
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerContentTypeUnsupported) Error() string {
|
||||||
|
return fmt.Sprintf("unsupported Content-Type header '%s'", e.ct)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerSDPInvalid is returned in case the SDP is invalid.
|
||||||
|
type ErrServerSDPInvalid struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerSDPInvalid) Error() string {
|
||||||
|
return fmt.Sprintf("invalid SDP: %v", e.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerSDPNoTracksDefined is returned in case the SDP has no tracks defined.
|
||||||
|
type ErrServerSDPNoTracksDefined struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerSDPNoTracksDefined) Error() string {
|
||||||
|
return "no tracks defined in the SDP"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerTransportHeaderInvalid is returned in case the transport header is invalid.
|
||||||
|
type ErrServerTransportHeaderInvalid struct {
|
||||||
|
err error
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerTransportHeaderInvalid) Error() string {
|
||||||
|
return fmt.Sprintf("invalid transport header: %v", e.err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerTrackAlreadySetup is returned in case a track has already been setup.
|
||||||
|
type ErrServerTrackAlreadySetup struct {
|
||||||
|
trackID int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerTrackAlreadySetup) Error() string {
|
||||||
|
return fmt.Sprintf("track %d has already been setup", e.trackID)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerTransportHeaderWrongMode is returned in case the transport header contains a wrong mode.
|
||||||
|
type ErrServerTransportHeaderWrongMode struct {
|
||||||
|
mode *headers.TransportMode
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerTransportHeaderWrongMode) Error() string {
|
||||||
|
return fmt.Sprintf("transport header contains a wrong mode (%v)", e.mode)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerTransportHeaderNoClientPorts is returned in case the transport header doesn't contain client ports.
|
||||||
|
type ErrServerTransportHeaderNoClientPorts struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerTransportHeaderNoClientPorts) Error() string {
|
||||||
|
return "transport header does not contain client ports"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerTransportHeaderNoInterleavedIDs is returned in case the transport header doesn't contain interleaved IDs.
|
||||||
|
type ErrServerTransportHeaderNoInterleavedIDs struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerTransportHeaderNoInterleavedIDs) Error() string {
|
||||||
|
return "transport header does not contain interleaved ids"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerTransportHeaderWrongInterleavedIDs is returned in case the transport header contains wrong interleaved IDs.
|
||||||
|
type ErrServerTransportHeaderWrongInterleavedIDs struct {
|
||||||
|
expected [2]int
|
||||||
|
value [2]int
|
||||||
|
}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerTransportHeaderWrongInterleavedIDs) Error() string {
|
||||||
|
return fmt.Sprintf("wrong interleaved ids, expected %v, got %v", e.expected, e.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerTracksDifferentProtocols is returned in case the client is trying to setup tracks with different protocols.
|
||||||
|
type ErrServerTracksDifferentProtocols struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerTracksDifferentProtocols) Error() string {
|
||||||
|
return "can't setup tracks with different protocols"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerNoTracksSetup is returned in case no tracks have been setup.
|
||||||
|
type ErrServerNoTracksSetup struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerNoTracksSetup) Error() string {
|
||||||
|
return "no tracks have been setup"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerNotAllAnnouncedTracksSetup is returned in case not all announced tracks have been setup.
|
||||||
|
type ErrServerNotAllAnnouncedTracksSetup struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerNotAllAnnouncedTracksSetup) Error() string {
|
||||||
|
return "not all announced tracks have been setup"
|
||||||
|
}
|
||||||
|
|
||||||
|
// ErrServerNoUDPPacketsRecently is returned when no UDP packets have been received recently.
|
||||||
|
type ErrServerNoUDPPacketsRecently struct{}
|
||||||
|
|
||||||
|
// Error implements the error interface.
|
||||||
|
func (e ErrServerNoUDPPacketsRecently) Error() string {
|
||||||
|
return "no UDP packets received recently (maybe there's a firewall/NAT in between)"
|
||||||
|
}
|
||||||
|
|
||||||
func stringsReverseIndex(s, substr string) int {
|
func stringsReverseIndex(s, substr string) int {
|
||||||
for i := len(s) - 1 - len(substr); i >= 0; i-- {
|
for i := len(s) - 1 - len(substr); i >= 0; i-- {
|
||||||
@@ -47,7 +201,7 @@ func setupGetTrackIDPathQuery(url *base.URL,
|
|||||||
|
|
||||||
pathAndQuery, ok := url.RTSPPathAndQuery()
|
pathAndQuery, ok := url.RTSPPathAndQuery()
|
||||||
if !ok {
|
if !ok {
|
||||||
return 0, "", "", fmt.Errorf("invalid URL (%s)", url)
|
return 0, "", "", ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if thMode == nil || *thMode == headers.TransportModePlay {
|
if thMode == nil || *thMode == headers.TransportModePlay {
|
||||||
@@ -356,9 +510,6 @@ func (sc *ServerConn) backgroundWrite() {
|
|||||||
case *base.Response:
|
case *base.Response:
|
||||||
sc.nconn.SetWriteDeadline(time.Now().Add(sc.conf.WriteTimeout))
|
sc.nconn.SetWriteDeadline(time.Now().Add(sc.conf.WriteTimeout))
|
||||||
w.Write(sc.bw)
|
w.Write(sc.bw)
|
||||||
|
|
||||||
default:
|
|
||||||
panic(fmt.Errorf("unsupported type: %T", what))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -374,8 +525,7 @@ func (sc *ServerConn) checkState(allowed map[ServerConnState]struct{}) error {
|
|||||||
allowedList[i] = a
|
allowedList[i] = a
|
||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return fmt.Errorf("must be in state %v, while is in state %v",
|
return ErrServerWrongState{allowedList, sc.state}
|
||||||
allowedList, sc.state)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// NetConn returns the underlying net.Conn.
|
// NetConn returns the underlying net.Conn.
|
||||||
@@ -467,7 +617,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
Header: base.Header{},
|
Header: base.Header{},
|
||||||
}, errServerCSeqMissing
|
}, ErrServerCSeqMissing{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sc.readHandlers.OnRequest != nil {
|
if sc.readHandlers.OnRequest != nil {
|
||||||
@@ -481,7 +631,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -540,7 +690,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -579,33 +729,33 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok || len(ct) != 1 {
|
if !ok || len(ct) != 1 {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, errors.New("Content-Type header is missing")
|
}, ErrServerContentTypeMissing{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ct[0] != "application/sdp" {
|
if ct[0] != "application/sdp" {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("unsupported Content-Type '%s'", ct)
|
}, ErrServerContentTypeUnsupported{ct}
|
||||||
}
|
}
|
||||||
|
|
||||||
tracks, err := ReadTracks(req.Body, req.URL)
|
tracks, err := ReadTracks(req.Body, req.URL)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid SDP: %s", err)
|
}, ErrServerSDPInvalid{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(tracks) == 0 {
|
if len(tracks) == 0 {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, errors.New("no tracks defined")
|
}, ErrServerSDPNoTracksDefined{}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPath()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -679,7 +829,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("transport header: %s", err)
|
}, ErrServerTransportHeaderInvalid{err}
|
||||||
}
|
}
|
||||||
|
|
||||||
if th.Delivery != nil && *th.Delivery == base.StreamDeliveryMulticast {
|
if th.Delivery != nil && *th.Delivery == base.StreamDeliveryMulticast {
|
||||||
@@ -699,7 +849,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if _, ok := sc.setuppedTracks[trackID]; ok {
|
if _, ok := sc.setuppedTracks[trackID]; ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("track %d has already been setup", trackID)
|
}, ErrServerTrackAlreadySetup{trackID}
|
||||||
}
|
}
|
||||||
|
|
||||||
switch sc.state {
|
switch sc.state {
|
||||||
@@ -707,14 +857,14 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if th.Mode != nil && *th.Mode != headers.TransportModePlay {
|
if th.Mode != nil && *th.Mode != headers.TransportModePlay {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("transport header must contain mode=play or not contain a mode")
|
}, ErrServerTransportHeaderWrongMode{th.Mode}
|
||||||
}
|
}
|
||||||
|
|
||||||
default: // record
|
default: // record
|
||||||
if th.Mode == nil || *th.Mode != headers.TransportModeRecord {
|
if th.Mode == nil || *th.Mode != headers.TransportModeRecord {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("transport header does not contain mode=record")
|
}, ErrServerTransportHeaderWrongMode{th.Mode}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -728,29 +878,29 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if th.ClientPorts == nil {
|
if th.ClientPorts == nil {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("transport header does not have valid client ports (%v)", req.Header["Transport"])
|
}, ErrServerTransportHeaderNoClientPorts{}
|
||||||
}
|
}
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
if th.InterleavedIds == nil {
|
if th.InterleavedIDs == nil {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("transport header does not contain the interleaved field")
|
}, ErrServerTransportHeaderNoInterleavedIDs{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if th.InterleavedIds[0] != (trackID*2) ||
|
if th.InterleavedIDs[0] != (trackID*2) ||
|
||||||
th.InterleavedIds[1] != (1+trackID*2) {
|
th.InterleavedIDs[1] != (1+trackID*2) {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("wrong interleaved ids, expected [%v %v], got %v",
|
}, ErrServerTransportHeaderWrongInterleavedIDs{
|
||||||
(trackID * 2), (1 + trackID*2), *th.InterleavedIds)
|
[2]int{(trackID * 2), (1 + trackID*2)}, *th.InterleavedIDs}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if sc.setupProtocol != nil && *sc.setupProtocol != th.Protocol {
|
if sc.setupProtocol != nil && *sc.setupProtocol != th.Protocol {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("can't setup tracks with different protocols")
|
}, ErrServerTracksDifferentProtocols{}
|
||||||
}
|
}
|
||||||
|
|
||||||
res, err := sc.readHandlers.OnSetup(&ServerConnSetupCtx{
|
res, err := sc.readHandlers.OnSetup(&ServerConnSetupCtx{
|
||||||
@@ -795,7 +945,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
}
|
}
|
||||||
res.Header["Transport"] = headers.Transport{
|
res.Header["Transport"] = headers.Transport{
|
||||||
Protocol: StreamProtocolTCP,
|
Protocol: StreamProtocolTCP,
|
||||||
InterleavedIds: th.InterleavedIds,
|
InterleavedIDs: th.InterleavedIDs,
|
||||||
}.Write()
|
}.Write()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -837,14 +987,14 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if len(sc.setuppedTracks) == 0 {
|
if len(sc.setuppedTracks) == 0 {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("no tracks have been setup")
|
}, ErrServerNoTracksSetup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPath()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// path can end with a slash due to Content-Base, remove it
|
// path can end with a slash due to Content-Base, remove it
|
||||||
@@ -880,20 +1030,20 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if len(sc.setuppedTracks) == 0 {
|
if len(sc.setuppedTracks) == 0 {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("no tracks have been setup")
|
}, ErrServerNoTracksSetup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(sc.setuppedTracks) != len(sc.announcedTracks) {
|
if len(sc.setuppedTracks) != len(sc.announcedTracks) {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("not all announced tracks have been setup")
|
}, ErrServerNotAllAnnouncedTracksSetup{}
|
||||||
}
|
}
|
||||||
|
|
||||||
pathAndQuery, ok := req.URL.RTSPPath()
|
pathAndQuery, ok := req.URL.RTSPPath()
|
||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// path can end with a slash due to Content-Base, remove it
|
// path can end with a slash due to Content-Base, remove it
|
||||||
@@ -933,7 +1083,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// path can end with a slash due to Content-Base, remove it
|
// path can end with a slash due to Content-Base, remove it
|
||||||
@@ -968,7 +1118,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -995,7 +1145,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -1013,7 +1163,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
if !ok {
|
if !ok {
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusBadRequest,
|
StatusCode: base.StatusBadRequest,
|
||||||
}, fmt.Errorf("invalid URL (%s)", req.URL)
|
}, ErrServerNoPath{}
|
||||||
}
|
}
|
||||||
|
|
||||||
path, query := base.PathSplitQuery(pathAndQuery)
|
path, query := base.PathSplitQuery(pathAndQuery)
|
||||||
@@ -1027,7 +1177,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) {
|
|||||||
|
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
StatusCode: base.StatusOK,
|
StatusCode: base.StatusOK,
|
||||||
}, ErrServerTeardown
|
}, ErrServerTeardown{}
|
||||||
}
|
}
|
||||||
|
|
||||||
return &base.Response{
|
return &base.Response{
|
||||||
@@ -1046,7 +1196,7 @@ func (sc *ServerConn) backgroundRead() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// add cseq
|
// add cseq
|
||||||
if err != errServerCSeqMissing {
|
if _, ok := err.(ErrServerCSeqMissing); !ok {
|
||||||
res.Header["CSeq"] = req.Header["CSeq"]
|
res.Header["CSeq"] = req.Header["CSeq"]
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1136,7 +1286,7 @@ outer:
|
|||||||
err := req.Read(sc.br)
|
err := req.Read(sc.br)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if atomic.LoadInt32(&sc.udpTimeout) == 1 {
|
if atomic.LoadInt32(&sc.udpTimeout) == 1 {
|
||||||
errRet = fmt.Errorf("no UDP packets received recently (maybe there's a firewall/NAT in between)")
|
errRet = ErrServerNoUDPPacketsRecently{}
|
||||||
} else {
|
} else {
|
||||||
errRet = err
|
errRet = err
|
||||||
}
|
}
|
||||||
|
@@ -202,9 +202,11 @@ func (ts *testServ) handleConn(conn *ServerConn) {
|
|||||||
OnRecord: onRecord,
|
OnRecord: onRecord,
|
||||||
OnFrame: onFrame,
|
OnFrame: onFrame,
|
||||||
})
|
})
|
||||||
if err != io.EOF && err != ErrServerTeardown {
|
if err != io.EOF {
|
||||||
|
if _, ok := err.(ErrServerTeardown); !ok {
|
||||||
fmt.Println("ERR", err)
|
fmt.Println("ERR", err)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ts.mutex.Lock()
|
ts.mutex.Lock()
|
||||||
defer ts.mutex.Unlock()
|
defer ts.mutex.Unlock()
|
||||||
@@ -464,7 +466,8 @@ func TestServerConnTeardownResponse(t *testing.T) {
|
|||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
err = <-conn.Read(ServerConnReadHandlers{})
|
err = <-conn.Read(ServerConnReadHandlers{})
|
||||||
require.Equal(t, ErrServerTeardown, err)
|
_, ok := err.(ErrServerTeardown)
|
||||||
|
require.Equal(t, true, ok)
|
||||||
}()
|
}()
|
||||||
|
|
||||||
conn, err := net.Dial("tcp", "localhost:8554")
|
conn, err := net.Dial("tcp", "localhost:8554")
|
||||||
|
@@ -161,7 +161,7 @@ func TestServerConnPublishSetupPath(t *testing.T) {
|
|||||||
v := headers.TransportModeRecord
|
v := headers.TransportModeRecord
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -262,7 +262,7 @@ func TestServerConnPublishSetupDifferentPaths(t *testing.T) {
|
|||||||
v := headers.TransportModeRecord
|
v := headers.TransportModeRecord
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -360,7 +360,7 @@ func TestServerConnPublishSetupDouble(t *testing.T) {
|
|||||||
v := headers.TransportModeRecord
|
v := headers.TransportModeRecord
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -482,7 +482,7 @@ func TestServerConnPublishRecordPartialTracks(t *testing.T) {
|
|||||||
v := headers.TransportModeRecord
|
v := headers.TransportModeRecord
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -632,7 +632,7 @@ func TestServerConnPublishReceivePackets(t *testing.T) {
|
|||||||
inTH.ClientPorts = &[2]int{35466, 35467}
|
inTH.ClientPorts = &[2]int{35466, 35467}
|
||||||
} else {
|
} else {
|
||||||
inTH.Protocol = StreamProtocolTCP
|
inTH.Protocol = StreamProtocolTCP
|
||||||
inTH.InterleavedIds = &[2]int{0, 1}
|
inTH.InterleavedIDs = &[2]int{0, 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
|
@@ -104,7 +104,7 @@ func TestServerConnReadSetupPath(t *testing.T) {
|
|||||||
v := headers.TransportModePlay
|
v := headers.TransportModePlay
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{ca.trackID * 2, (ca.trackID * 2) + 1},
|
InterleavedIDs: &[2]int{ca.trackID * 2, (ca.trackID * 2) + 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -172,7 +172,7 @@ func TestServerConnReadSetupDifferentPaths(t *testing.T) {
|
|||||||
v := headers.TransportModePlay
|
v := headers.TransportModePlay
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -190,7 +190,7 @@ func TestServerConnReadSetupDifferentPaths(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, base.StatusOK, res.StatusCode)
|
require.Equal(t, base.StatusOK, res.StatusCode)
|
||||||
|
|
||||||
th.InterleavedIds = &[2]int{2, 3}
|
th.InterleavedIDs = &[2]int{2, 3}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
Method: base.Setup,
|
Method: base.Setup,
|
||||||
@@ -253,7 +253,7 @@ func TestServerConnReadSetupDouble(t *testing.T) {
|
|||||||
v := headers.TransportModePlay
|
v := headers.TransportModePlay
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -271,7 +271,7 @@ func TestServerConnReadSetupDouble(t *testing.T) {
|
|||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Equal(t, base.StatusOK, res.StatusCode)
|
require.Equal(t, base.StatusOK, res.StatusCode)
|
||||||
|
|
||||||
th.InterleavedIds = &[2]int{2, 3}
|
th.InterleavedIDs = &[2]int{2, 3}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
Method: base.Setup,
|
Method: base.Setup,
|
||||||
@@ -364,7 +364,7 @@ func TestServerConnReadReceivePackets(t *testing.T) {
|
|||||||
inTH.ClientPorts = &[2]int{35466, 35467}
|
inTH.ClientPorts = &[2]int{35466, 35467}
|
||||||
} else {
|
} else {
|
||||||
inTH.Protocol = StreamProtocolTCP
|
inTH.Protocol = StreamProtocolTCP
|
||||||
inTH.InterleavedIds = &[2]int{0, 1}
|
inTH.InterleavedIDs = &[2]int{0, 1}
|
||||||
}
|
}
|
||||||
|
|
||||||
err = base.Request{
|
err = base.Request{
|
||||||
@@ -501,7 +501,7 @@ func TestServerConnReadTCPResponseBeforeFrames(t *testing.T) {
|
|||||||
v := headers.TransportModePlay
|
v := headers.TransportModePlay
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}.Write(),
|
}.Write(),
|
||||||
},
|
},
|
||||||
}.Write(bconn.Writer)
|
}.Write(bconn.Writer)
|
||||||
@@ -606,7 +606,7 @@ func TestServerConnReadPlayMultiple(t *testing.T) {
|
|||||||
v := headers.TransportModePlay
|
v := headers.TransportModePlay
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}.Write(),
|
}.Write(),
|
||||||
},
|
},
|
||||||
}.Write(bconn.Writer)
|
}.Write(bconn.Writer)
|
||||||
@@ -725,7 +725,7 @@ func TestServerConnReadPauseMultiple(t *testing.T) {
|
|||||||
v := headers.TransportModePlay
|
v := headers.TransportModePlay
|
||||||
return &v
|
return &v
|
||||||
}(),
|
}(),
|
||||||
InterleavedIds: &[2]int{0, 1},
|
InterleavedIDs: &[2]int{0, 1},
|
||||||
}.Write(),
|
}.Write(),
|
||||||
},
|
},
|
||||||
}.Write(bconn.Writer)
|
}.Write(bconn.Writer)
|
||||||
|
Reference in New Issue
Block a user