From 437b4cc87e5e6e64f656d96bd9d77ca848b488ee Mon Sep 17 00:00:00 2001 From: aler9 <46489434+aler9@users.noreply.github.com> Date: Sun, 21 Mar 2021 11:19:35 +0100 Subject: [PATCH] move errors into subpackage --- clientconn.go | 175 ++++------------------------ clientconnpublish.go | 7 +- clientconnread.go | 8 +- pkg/liberrors/client.go | 153 +++++++++++++++++++++++++ pkg/liberrors/liberrors.go | 2 + pkg/liberrors/server.go | 169 +++++++++++++++++++++++++++ serverconn.go | 226 ++++++------------------------------- serverconn_test.go | 5 +- 8 files changed, 391 insertions(+), 354 deletions(-) create mode 100644 pkg/liberrors/client.go create mode 100644 pkg/liberrors/liberrors.go create mode 100644 pkg/liberrors/server.go diff --git a/clientconn.go b/clientconn.go index 4874ff4b..435936fd 100644 --- a/clientconn.go +++ b/clientconn.go @@ -21,6 +21,7 @@ import ( "github.com/aler9/gortsplib/pkg/auth" "github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/headers" + "github.com/aler9/gortsplib/pkg/liberrors" "github.com/aler9/gortsplib/pkg/multibuffer" "github.com/aler9/gortsplib/pkg/rtcpreceiver" "github.com/aler9/gortsplib/pkg/rtcpsender" @@ -35,142 +36,6 @@ const ( clientConnUDPKeepalivePeriod = 30 * time.Second ) -// ErrClientWrongState is returned in case of a wrong client state. -type ErrClientWrongState struct { - allowedList []clientConnState - state clientConnState -} - -// Error implements the error interface. -func (e ErrClientWrongState) Error() string { - return fmt.Sprintf("must be in state %v, while is in state %v", - e.allowedList, e.state) -} - -// ErrClientSessionHeaderInvalid is returned in case of an invalid session header. -type ErrClientSessionHeaderInvalid struct { - err error -} - -// Error implements the error interface. -func (e ErrClientSessionHeaderInvalid) Error() string { - return fmt.Sprintf("invalid session header: %v", e.err) -} - -// ErrClientWrongStatusCode is returned in case of a wrong status code. -type ErrClientWrongStatusCode struct { - code base.StatusCode - message string -} - -// Error implements the error interface. -func (e ErrClientWrongStatusCode) Error() string { - return fmt.Sprintf("wrong status code: %d (%s)", e.code, e.message) -} - -// ErrClientContentTypeMissing is returned in case the Content-Type header is missing. -type ErrClientContentTypeMissing struct{} - -// Error implements the error interface. -func (e ErrClientContentTypeMissing) Error() string { - return "Content-Type header is missing" -} - -// ErrClientContentTypeUnsupported is returned in case the Content-Type header is unsupported. -type ErrClientContentTypeUnsupported struct { - ct base.HeaderValue -} - -// Error implements the error interface. -func (e ErrClientContentTypeUnsupported) Error() string { - return fmt.Sprintf("unsupported Content-Type header '%v'", e.ct) -} - -// ErrClientCannotReadPublishAtSameTime is returned when the client is trying to read and publish at the same time. -type ErrClientCannotReadPublishAtSameTime struct{} - -// Error implements the error interface. -func (e ErrClientCannotReadPublishAtSameTime) Error() string { - return "cannot read and publish at the same time" -} - -// ErrClientCannotSetupTracksDifferentURLs is returned when the client is trying to setup tracks with different base URLs. -type ErrClientCannotSetupTracksDifferentURLs struct{} - -// Error implements the error interface. -func (e ErrClientCannotSetupTracksDifferentURLs) Error() string { - return "cannot setup tracks with different base URLs" -} - -// ErrClientUDPPortsZero is returned when one of the UDP ports is zero. -type ErrClientUDPPortsZero struct{} - -// Error implements the error interface. -func (e ErrClientUDPPortsZero) Error() string { - return "rtpPort and rtcpPort must be both zero or non-zero" -} - -// ErrClientUDPPortsNotConsecutive is returned when the two UDP ports are not consecutive. -type ErrClientUDPPortsNotConsecutive struct{} - -// Error implements the error interface. -func (e ErrClientUDPPortsNotConsecutive) Error() string { - return "rtcpPort must be rtpPort + 1" -} - -// ErrClientServerPortsZero is returned when one of the server ports is zero. -type ErrClientServerPortsZero struct{} - -// Error implements the error interface. -func (e ErrClientServerPortsZero) Error() string { - return "server ports must be both zero or both not zero" -} - -// ErrClientServerPortsNotProvided is returned in case the server ports have not been provided. -type ErrClientServerPortsNotProvided struct{} - -// Error implements the error interface. -func (e ErrClientServerPortsNotProvided) Error() string { - return "server ports have not been provided. Use AnyPortEnable to communicate with this server" -} - -// ErrClientTransportHeaderNoInterleavedIDs is returned in case the transport header doesn't contain interleaved IDs. -type ErrClientTransportHeaderNoInterleavedIDs struct{} - -// Error implements the error interface. -func (e ErrClientTransportHeaderNoInterleavedIDs) Error() string { - return "transport header does not contain interleaved IDs" -} - -// ErrClientTransportHeaderWrongInterleavedIDs is returned in case the transport header contains wrong interleaved IDs. -type ErrClientTransportHeaderWrongInterleavedIDs struct { - expected [2]int - value [2]int -} - -// Error implements the error interface. -func (e ErrClientTransportHeaderWrongInterleavedIDs) Error() string { - return fmt.Sprintf("wrong interleaved IDs, expected %v, got %v", e.expected, e.value) -} - -// ErrClientNoUDPPacketsRecently is returned when no UDP packets have been received recently. -type ErrClientNoUDPPacketsRecently struct{} - -// Error implements the error interface. -func (e ErrClientNoUDPPacketsRecently) Error() string { - return "no UDP packets received recently (maybe there's a firewall/NAT in between)" -} - -// ErrClientRTPInfoInvalid is returned in case of an invalid RTP-Info. -type ErrClientRTPInfoInvalid struct { - err error -} - -// Error implements the error interface. -func (e ErrClientRTPInfoInvalid) Error() string { - return fmt.Sprintf("unable to parse RTP-Info: %v", e.err) -} - type clientConnState int const ( @@ -329,13 +194,13 @@ func (c *ClientConn) checkState(allowed map[clientConnState]struct{}) error { return nil } - allowedList := make([]clientConnState, len(allowed)) + allowedList := make([]fmt.Stringer, len(allowed)) i := 0 for a := range allowed { allowedList[i] = a i++ } - return ErrClientWrongState{allowedList, c.state} + return liberrors.ErrClientWrongState{AllowedList: allowedList, State: c.state} } // NetConn returns the underlying net.Conn. @@ -406,7 +271,7 @@ func (c *ClientConn) Do(req *base.Request) (*base.Response, error) { var sx headers.Session err := sx.Read(v) if err != nil { - return nil, ErrClientSessionHeaderInvalid{err} + return nil, liberrors.ErrClientSessionHeaderInvalid{Err: err} } c.session = sx.Session } @@ -454,7 +319,7 @@ func (c *ClientConn) Options(u *base.URL) (*base.Response, error) { if res.StatusCode == base.StatusNotFound { return res, nil } - return res, ErrClientWrongStatusCode{res.StatusCode, res.StatusMessage} + return res, liberrors.ErrClientWrongStatusCode{Code: res.StatusCode, Message: res.StatusMessage} } c.getParameterSupported = func() bool { @@ -524,16 +389,16 @@ func (c *ClientConn) Describe(u *base.URL) (Tracks, *base.Response, error) { return c.Describe(u) } - return nil, res, ErrClientWrongStatusCode{res.StatusCode, res.StatusMessage} + return nil, res, liberrors.ErrClientWrongStatusCode{Code: res.StatusCode, Message: res.StatusMessage} } ct, ok := res.Header["Content-Type"] if !ok || len(ct) != 1 { - return nil, nil, ErrClientContentTypeMissing{} + return nil, nil, liberrors.ErrClientContentTypeMissing{} } if ct[0] != "application/sdp" { - return nil, nil, ErrClientContentTypeUnsupported{ct} + return nil, nil, liberrors.ErrClientContentTypeUnsupported{CT: ct} } tracks, err := ReadTracks(res.Body, u) @@ -561,11 +426,11 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track, if (mode == headers.TransportModeRecord && c.state != clientConnStatePreRecord) || (mode == headers.TransportModePlay && c.state != clientConnStatePrePlay && c.state != clientConnStateInitial) { - return nil, ErrClientCannotReadPublishAtSameTime{} + return nil, liberrors.ErrClientCannotReadPublishAtSameTime{} } if c.streamURL != nil && *track.BaseURL != *c.streamURL { - return nil, ErrClientCannotSetupTracksDifferentURLs{} + return nil, liberrors.ErrClientCannotSetupTracksDifferentURLs{} } var rtpListener *clientConnUDPListener @@ -604,11 +469,11 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track, if proto == base.StreamProtocolUDP { if (rtpPort == 0 && rtcpPort != 0) || (rtpPort != 0 && rtcpPort == 0) { - return nil, ErrClientUDPPortsZero{} + return nil, liberrors.ErrClientUDPPortsZero{} } if rtpPort != 0 && rtcpPort != (rtpPort+1) { - return nil, ErrClientUDPPortsNotConsecutive{} + return nil, liberrors.ErrClientUDPPortsNotConsecutive{} } var err error @@ -700,7 +565,7 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track, return c.Setup(headers.TransportModePlay, track, 0, 0) } - return res, ErrClientWrongStatusCode{res.StatusCode, res.StatusMessage} + return res, liberrors.ErrClientWrongStatusCode{Code: res.StatusCode, Message: res.StatusMessage} } var thRes headers.Transport @@ -710,7 +575,7 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track, rtpListener.close() rtcpListener.close() } - return nil, fmt.Errorf("transport header: %s", err) + return nil, liberrors.ErrClientTransportHeaderInvalid{Err: err} } if proto == StreamProtocolUDP { @@ -719,7 +584,7 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track, (thRes.ServerPorts[0] != 0 && thRes.ServerPorts[1] == 0) { rtpListener.close() rtcpListener.close() - return nil, ErrClientServerPortsZero{} + return nil, liberrors.ErrClientServerPortsZero{} } } @@ -727,18 +592,19 @@ func (c *ClientConn) Setup(mode headers.TransportMode, track *Track, if thRes.ServerPorts == nil || (thRes.ServerPorts[0] == 0 && thRes.ServerPorts[1] == 0) { rtpListener.close() rtcpListener.close() - return nil, ErrClientServerPortsNotProvided{} + return nil, liberrors.ErrClientServerPortsNotProvided{} } } } else { if thRes.InterleavedIDs == nil { - return nil, ErrClientTransportHeaderNoInterleavedIDs{} + return nil, liberrors.ErrClientTransportHeaderNoInterleavedIDs{} } if thRes.InterleavedIDs[0] != th.InterleavedIDs[0] || thRes.InterleavedIDs[1] != th.InterleavedIDs[1] { - return nil, ErrClientTransportHeaderWrongInterleavedIDs{*th.InterleavedIDs, *thRes.InterleavedIDs} + return nil, liberrors.ErrClientTransportHeaderWrongInterleavedIDs{ + Expected: *th.InterleavedIDs, Value: *thRes.InterleavedIDs} } } @@ -811,7 +677,8 @@ func (c *ClientConn) Pause() (*base.Response, error) { } if res.StatusCode != base.StatusOK { - return res, ErrClientWrongStatusCode{res.StatusCode, res.StatusMessage} + return res, liberrors.ErrClientWrongStatusCode{ + Code: res.StatusCode, Message: res.StatusMessage} } switch c.state { diff --git a/clientconnpublish.go b/clientconnpublish.go index dca84c3d..75072162 100644 --- a/clientconnpublish.go +++ b/clientconnpublish.go @@ -8,6 +8,7 @@ import ( psdp "github.com/pion/sdp/v3" "github.com/aler9/gortsplib/pkg/base" + "github.com/aler9/gortsplib/pkg/liberrors" ) // Announce writes an ANNOUNCE request and reads a Response. @@ -43,7 +44,8 @@ func (c *ClientConn) Announce(u *base.URL, tracks Tracks) (*base.Response, error } if res.StatusCode != base.StatusOK { - return nil, ErrClientWrongStatusCode{res.StatusCode, res.StatusMessage} + return nil, liberrors.ErrClientWrongStatusCode{ + Code: res.StatusCode, Message: res.StatusMessage} } c.streamURL = u @@ -71,7 +73,8 @@ func (c *ClientConn) Record() (*base.Response, error) { } if res.StatusCode != base.StatusOK { - return nil, ErrClientWrongStatusCode{res.StatusCode, res.StatusMessage} + return nil, liberrors.ErrClientWrongStatusCode{ + Code: res.StatusCode, Message: res.StatusMessage} } c.state = clientConnStateRecord diff --git a/clientconnread.go b/clientconnread.go index d81a04a5..67362a3a 100644 --- a/clientconnread.go +++ b/clientconnread.go @@ -7,6 +7,7 @@ import ( "github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/headers" + "github.com/aler9/gortsplib/pkg/liberrors" ) // Play writes a PLAY request and reads a Response. @@ -28,14 +29,15 @@ func (c *ClientConn) Play() (*base.Response, error) { } if res.StatusCode != base.StatusOK { - return nil, ErrClientWrongStatusCode{res.StatusCode, res.StatusMessage} + return nil, liberrors.ErrClientWrongStatusCode{ + Code: res.StatusCode, Message: res.StatusMessage} } if v, ok := res.Header["RTP-Info"]; ok { var ri headers.RTPInfo err := ri.Read(v) if err != nil { - return nil, ErrClientRTPInfoInvalid{err} + return nil, liberrors.ErrClientRTPInfoInvalid{Err: err} } c.rtpInfo = &ri } @@ -144,7 +146,7 @@ func (c *ClientConn) backgroundPlayUDP(done chan error) { if now.Sub(last) >= c.conf.ReadTimeout { c.nconn.SetReadDeadline(time.Now()) <-readerDone - returnError = ErrClientNoUDPPacketsRecently{} + returnError = liberrors.ErrClientNoUDPPacketsRecently{} return } } diff --git a/pkg/liberrors/client.go b/pkg/liberrors/client.go new file mode 100644 index 00000000..698af24d --- /dev/null +++ b/pkg/liberrors/client.go @@ -0,0 +1,153 @@ +package liberrors + +import ( + "fmt" + + "github.com/aler9/gortsplib/pkg/base" +) + +// ErrClientWrongState is returned in case of a wrong client state. +type ErrClientWrongState struct { + AllowedList []fmt.Stringer + State fmt.Stringer +} + +// Error implements the error interface. +func (e ErrClientWrongState) Error() string { + return fmt.Sprintf("must be in state %v, while is in state %v", + e.AllowedList, e.State) +} + +// ErrClientSessionHeaderInvalid is returned in case of an invalid session header. +type ErrClientSessionHeaderInvalid struct { + Err error +} + +// Error implements the error interface. +func (e ErrClientSessionHeaderInvalid) Error() string { + return fmt.Sprintf("invalid session header: %v", e.Err) +} + +// ErrClientWrongStatusCode is returned in case of a wrong status code. +type ErrClientWrongStatusCode struct { + Code base.StatusCode + Message string +} + +// Error implements the error interface. +func (e ErrClientWrongStatusCode) Error() string { + return fmt.Sprintf("wrong status code: %d (%s)", e.Code, e.Message) +} + +// ErrClientContentTypeMissing is returned in case the Content-Type header is missing. +type ErrClientContentTypeMissing struct{} + +// Error implements the error interface. +func (e ErrClientContentTypeMissing) Error() string { + return "Content-Type header is missing" +} + +// ErrClientContentTypeUnsupported is returned in case the Content-Type header is unsupported. +type ErrClientContentTypeUnsupported struct { + CT base.HeaderValue +} + +// Error implements the error interface. +func (e ErrClientContentTypeUnsupported) Error() string { + return fmt.Sprintf("unsupported Content-Type header '%v'", e.CT) +} + +// ErrClientCannotReadPublishAtSameTime is returned when the client is trying to read and publish at the same time. +type ErrClientCannotReadPublishAtSameTime struct{} + +// Error implements the error interface. +func (e ErrClientCannotReadPublishAtSameTime) Error() string { + return "cannot read and publish at the same time" +} + +// ErrClientCannotSetupTracksDifferentURLs is returned when the client is trying to setup tracks with different base URLs. +type ErrClientCannotSetupTracksDifferentURLs struct{} + +// Error implements the error interface. +func (e ErrClientCannotSetupTracksDifferentURLs) Error() string { + return "cannot setup tracks with different base URLs" +} + +// ErrClientUDPPortsZero is returned when one of the UDP ports is zero. +type ErrClientUDPPortsZero struct{} + +// Error implements the error interface. +func (e ErrClientUDPPortsZero) Error() string { + return "rtpPort and rtcpPort must be both zero or non-zero" +} + +// ErrClientUDPPortsNotConsecutive is returned when the two UDP ports are not consecutive. +type ErrClientUDPPortsNotConsecutive struct{} + +// Error implements the error interface. +func (e ErrClientUDPPortsNotConsecutive) Error() string { + return "rtcpPort must be rtpPort + 1" +} + +// ErrClientServerPortsZero is returned when one of the server ports is zero. +type ErrClientServerPortsZero struct{} + +// Error implements the error interface. +func (e ErrClientServerPortsZero) Error() string { + return "server ports must be both zero or both not zero" +} + +// ErrClientServerPortsNotProvided is returned in case the server ports have not been provided. +type ErrClientServerPortsNotProvided struct{} + +// Error implements the error interface. +func (e ErrClientServerPortsNotProvided) Error() string { + return "server ports have not been provided. Use AnyPortEnable to communicate with this server" +} + +// ErrClientTransportHeaderInvalid is returned in case the transport header is invalid. +type ErrClientTransportHeaderInvalid struct { + Err error +} + +// Error implements the error interface. +func (e ErrClientTransportHeaderInvalid) Error() string { + return fmt.Sprintf("invalid transport header: %v", e.Err) +} + +// ErrClientTransportHeaderNoInterleavedIDs is returned in case the transport header doesn't contain interleaved IDs. +type ErrClientTransportHeaderNoInterleavedIDs struct{} + +// Error implements the error interface. +func (e ErrClientTransportHeaderNoInterleavedIDs) Error() string { + return "transport header does not contain interleaved IDs" +} + +// ErrClientTransportHeaderWrongInterleavedIDs is returned in case the transport header contains wrong interleaved IDs. +type ErrClientTransportHeaderWrongInterleavedIDs struct { + Expected [2]int + Value [2]int +} + +// Error implements the error interface. +func (e ErrClientTransportHeaderWrongInterleavedIDs) Error() string { + return fmt.Sprintf("wrong interleaved IDs, expected %v, got %v", e.Expected, e.Value) +} + +// ErrClientNoUDPPacketsRecently is returned when no UDP packets have been received recently. +type ErrClientNoUDPPacketsRecently struct{} + +// Error implements the error interface. +func (e ErrClientNoUDPPacketsRecently) Error() string { + return "no UDP packets received recently (maybe there's a firewall/NAT in between)" +} + +// ErrClientRTPInfoInvalid is returned in case of an invalid RTP-Info. +type ErrClientRTPInfoInvalid struct { + Err error +} + +// Error implements the error interface. +func (e ErrClientRTPInfoInvalid) Error() string { + return fmt.Sprintf("invalid RTP-Info: %v", e.Err) +} diff --git a/pkg/liberrors/liberrors.go b/pkg/liberrors/liberrors.go new file mode 100644 index 00000000..60cc731f --- /dev/null +++ b/pkg/liberrors/liberrors.go @@ -0,0 +1,2 @@ +// Package liberrors contains errors returned by the library. +package liberrors diff --git a/pkg/liberrors/server.go b/pkg/liberrors/server.go new file mode 100644 index 00000000..061f4479 --- /dev/null +++ b/pkg/liberrors/server.go @@ -0,0 +1,169 @@ +package liberrors + +import ( + "fmt" + + "github.com/aler9/gortsplib/pkg/base" + "github.com/aler9/gortsplib/pkg/headers" +) + +// ErrServerTeardown is returned in case of a teardown request. +type ErrServerTeardown struct{} + +// 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 []fmt.Stringer + State fmt.Stringer +} + +// 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 '%v'", 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)" +} diff --git a/serverconn.go b/serverconn.go index b501e130..347bcf15 100644 --- a/serverconn.go +++ b/serverconn.go @@ -12,6 +12,7 @@ import ( "github.com/aler9/gortsplib/pkg/base" "github.com/aler9/gortsplib/pkg/headers" + "github.com/aler9/gortsplib/pkg/liberrors" "github.com/aler9/gortsplib/pkg/multibuffer" "github.com/aler9/gortsplib/pkg/ringbuffer" "github.com/aler9/gortsplib/pkg/rtcpreceiver" @@ -24,167 +25,6 @@ const ( serverConnReceiverReportInterval = 10 * time.Second ) -// ErrServerTeardown is returned in case of a teardown request. -type ErrServerTeardown struct{} - -// 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 '%v'", 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 { for i := len(s) - 1 - len(substr); i >= 0; i-- { if s[i:i+len(substr)] == substr { @@ -201,7 +41,7 @@ func setupGetTrackIDPathQuery(url *base.URL, pathAndQuery, ok := url.RTSPPathAndQuery() if !ok { - return 0, "", "", ErrServerNoPath{} + return 0, "", "", liberrors.ErrServerNoPath{} } if thMode == nil || *thMode == headers.TransportModePlay { @@ -519,13 +359,13 @@ func (sc *ServerConn) checkState(allowed map[ServerConnState]struct{}) error { return nil } - allowedList := make([]ServerConnState, len(allowed)) + allowedList := make([]fmt.Stringer, len(allowed)) i := 0 for a := range allowed { allowedList[i] = a i++ } - return ErrServerWrongState{allowedList, sc.state} + return liberrors.ErrServerWrongState{AllowedList: allowedList, State: sc.state} } // NetConn returns the underlying net.Conn. @@ -617,7 +457,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { return &base.Response{ StatusCode: base.StatusBadRequest, Header: base.Header{}, - }, ErrServerCSeqMissing{} + }, liberrors.ErrServerCSeqMissing{} } if sc.readHandlers.OnRequest != nil { @@ -631,7 +471,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } path, query := base.PathSplitQuery(pathAndQuery) @@ -690,7 +530,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } path, query := base.PathSplitQuery(pathAndQuery) @@ -729,33 +569,33 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if !ok || len(ct) != 1 { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerContentTypeMissing{} + }, liberrors.ErrServerContentTypeMissing{} } if ct[0] != "application/sdp" { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerContentTypeUnsupported{ct} + }, liberrors.ErrServerContentTypeUnsupported{CT: ct} } tracks, err := ReadTracks(req.Body, req.URL) if err != nil { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerSDPInvalid{err} + }, liberrors.ErrServerSDPInvalid{Err: err} } if len(tracks) == 0 { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerSDPNoTracksDefined{} + }, liberrors.ErrServerSDPNoTracksDefined{} } pathAndQuery, ok := req.URL.RTSPPath() if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } path, query := base.PathSplitQuery(pathAndQuery) @@ -829,7 +669,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if err != nil { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTransportHeaderInvalid{err} + }, liberrors.ErrServerTransportHeaderInvalid{Err: err} } if th.Delivery != nil && *th.Delivery == base.StreamDeliveryMulticast { @@ -849,7 +689,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if _, ok := sc.setuppedTracks[trackID]; ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTrackAlreadySetup{trackID} + }, liberrors.ErrServerTrackAlreadySetup{TrackID: trackID} } switch sc.state { @@ -857,14 +697,14 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if th.Mode != nil && *th.Mode != headers.TransportModePlay { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTransportHeaderWrongMode{th.Mode} + }, liberrors.ErrServerTransportHeaderWrongMode{Mode: th.Mode} } default: // record if th.Mode == nil || *th.Mode != headers.TransportModeRecord { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTransportHeaderWrongMode{th.Mode} + }, liberrors.ErrServerTransportHeaderWrongMode{Mode: th.Mode} } } @@ -878,29 +718,29 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if th.ClientPorts == nil { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTransportHeaderNoClientPorts{} + }, liberrors.ErrServerTransportHeaderNoClientPorts{} } } else { if th.InterleavedIDs == nil { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTransportHeaderNoInterleavedIDs{} + }, liberrors.ErrServerTransportHeaderNoInterleavedIDs{} } if th.InterleavedIDs[0] != (trackID*2) || th.InterleavedIDs[1] != (1+trackID*2) { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTransportHeaderWrongInterleavedIDs{ - [2]int{(trackID * 2), (1 + trackID*2)}, *th.InterleavedIDs} + }, liberrors.ErrServerTransportHeaderWrongInterleavedIDs{ + Expected: [2]int{(trackID * 2), (1 + trackID*2)}, Value: *th.InterleavedIDs} } } if sc.setupProtocol != nil && *sc.setupProtocol != th.Protocol { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerTracksDifferentProtocols{} + }, liberrors.ErrServerTracksDifferentProtocols{} } res, err := sc.readHandlers.OnSetup(&ServerConnSetupCtx{ @@ -987,14 +827,14 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if len(sc.setuppedTracks) == 0 { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoTracksSetup{} + }, liberrors.ErrServerNoTracksSetup{} } pathAndQuery, ok := req.URL.RTSPPath() if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } // path can end with a slash due to Content-Base, remove it @@ -1030,20 +870,20 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if len(sc.setuppedTracks) == 0 { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoTracksSetup{} + }, liberrors.ErrServerNoTracksSetup{} } if len(sc.setuppedTracks) != len(sc.announcedTracks) { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNotAllAnnouncedTracksSetup{} + }, liberrors.ErrServerNotAllAnnouncedTracksSetup{} } pathAndQuery, ok := req.URL.RTSPPath() if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } // path can end with a slash due to Content-Base, remove it @@ -1083,7 +923,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } // path can end with a slash due to Content-Base, remove it @@ -1118,7 +958,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } path, query := base.PathSplitQuery(pathAndQuery) @@ -1145,7 +985,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } path, query := base.PathSplitQuery(pathAndQuery) @@ -1163,7 +1003,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { if !ok { return &base.Response{ StatusCode: base.StatusBadRequest, - }, ErrServerNoPath{} + }, liberrors.ErrServerNoPath{} } path, query := base.PathSplitQuery(pathAndQuery) @@ -1177,7 +1017,7 @@ func (sc *ServerConn) handleRequest(req *base.Request) (*base.Response, error) { return &base.Response{ StatusCode: base.StatusOK, - }, ErrServerTeardown{} + }, liberrors.ErrServerTeardown{} } return &base.Response{ @@ -1196,7 +1036,7 @@ func (sc *ServerConn) backgroundRead() error { } // add cseq - if _, ok := err.(ErrServerCSeqMissing); !ok { + if _, ok := err.(liberrors.ErrServerCSeqMissing); !ok { res.Header["CSeq"] = req.Header["CSeq"] } @@ -1286,7 +1126,7 @@ outer: err := req.Read(sc.br) if err != nil { if atomic.LoadInt32(&sc.udpTimeout) == 1 { - errRet = ErrServerNoUDPPacketsRecently{} + errRet = liberrors.ErrServerNoUDPPacketsRecently{} } else { errRet = err } diff --git a/serverconn_test.go b/serverconn_test.go index 14df2755..66adf8d3 100644 --- a/serverconn_test.go +++ b/serverconn_test.go @@ -13,6 +13,7 @@ import ( "github.com/stretchr/testify/require" "github.com/aler9/gortsplib/pkg/base" + "github.com/aler9/gortsplib/pkg/liberrors" ) type testServ struct { @@ -203,7 +204,7 @@ func (ts *testServ) handleConn(conn *ServerConn) { OnFrame: onFrame, }) if err != io.EOF { - if _, ok := err.(ErrServerTeardown); !ok { + if _, ok := err.(liberrors.ErrServerTeardown); !ok { fmt.Println("ERR", err) } } @@ -466,7 +467,7 @@ func TestServerConnTeardownResponse(t *testing.T) { defer conn.Close() err = <-conn.Read(ServerConnReadHandlers{}) - _, ok := err.(ErrServerTeardown) + _, ok := err.(liberrors.ErrServerTeardown) require.Equal(t, true, ok) }()