Fix RTPSender.SetReadDeadline crash

Add nil pointer check when calling SetReadDeadline. I don't believe this
can happen with WebRTC, but is possible with `ortc`.

A future improvement would be to cache the `SetReadDeadline` call. At
this time the complexity seems to outweight the reward.

Resolves #2889
This commit is contained in:
Sean DuBois
2025-09-12 10:57:27 -04:00
parent 634a904ba9
commit 6ef2888a26
3 changed files with 32 additions and 10 deletions

View File

@@ -244,6 +244,7 @@ var (
errRTPSenderTrackNil = errors.New("Track must not be nil") errRTPSenderTrackNil = errors.New("Track must not be nil")
errRTPSenderDTLSTransportNil = errors.New("DTLSTransport must not be nil") errRTPSenderDTLSTransportNil = errors.New("DTLSTransport must not be nil")
errRTPSenderSendAlreadyCalled = errors.New("Send has already been called") errRTPSenderSendAlreadyCalled = errors.New("Send has already been called")
errRTPSenderSendNotCalled = errors.New("Send has not been called")
errRTPSenderStopped = errors.New("Sender has already been stopped") errRTPSenderStopped = errors.New("Sender has already been stopped")
errRTPSenderTrackRemoved = errors.New("Sender Track has been removed or replaced to nil") errRTPSenderTrackRemoved = errors.New("Sender Track has been removed or replaced to nil")
errRTPSenderRidNil = errors.New("Sender cannot add encoding as rid is empty") errRTPSenderRidNil = errors.New("Sender cannot add encoding as rid is empty")

View File

@@ -470,6 +470,10 @@ func (r *RTPSender) ReadSimulcastRTCP(rid string) ([]rtcp.Packet, interceptor.At
// SetReadDeadline sets the deadline for the Read operation. // SetReadDeadline sets the deadline for the Read operation.
// Setting to zero means no deadline. // Setting to zero means no deadline.
func (r *RTPSender) SetReadDeadline(t time.Time) error { func (r *RTPSender) SetReadDeadline(t time.Time) error {
if r.trackEncodings[0].srtpStream == nil {
return errRTPSenderSendNotCalled
}
return r.trackEncodings[0].srtpStream.SetReadDeadline(t) return r.trackEncodings[0].srtpStream.SetReadDeadline(t)
} }

View File

@@ -504,6 +504,20 @@ func Test_RTPSender_RTX_Support(t *testing.T) {
}) })
} }
type TrackLocalCheckRTCPReaderOnBind struct {
*TrackLocalStaticSample
t *testing.T
bindCalled chan struct{}
}
func (s *TrackLocalCheckRTCPReaderOnBind) Bind(ctx TrackLocalContext) (RTPCodecParameters, error) {
assert.NotNil(s.t, ctx.RTCPReader())
p, err := s.TrackLocalStaticSample.Bind(ctx)
close(s.bindCalled)
return p, err
}
func Test_RTPSender_RTCPReader_Bind_Not_Nil(t *testing.T) { func Test_RTPSender_RTCPReader_Bind_Not_Nil(t *testing.T) {
track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion") track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
assert.NoError(t, err) assert.NoError(t, err)
@@ -528,16 +542,19 @@ func Test_RTPSender_RTCPReader_Bind_Not_Nil(t *testing.T) {
assert.NoError(t, peerConnection.Close()) assert.NoError(t, peerConnection.Close())
} }
type TrackLocalCheckRTCPReaderOnBind struct { func Test_RTPSender_SetReadDeadline_Crash(t *testing.T) {
*TrackLocalStaticSample stackA, stackB, err := newORTCPair()
t *testing.T assert.NoError(t, err)
bindCalled chan struct{}
}
func (s *TrackLocalCheckRTCPReaderOnBind) Bind(ctx TrackLocalContext) (RTPCodecParameters, error) { assert.NoError(t, signalORTCPair(stackA, stackB))
assert.NotNil(s.t, ctx.RTCPReader())
p, err := s.TrackLocalStaticSample.Bind(ctx)
close(s.bindCalled)
return p, err track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
assert.NoError(t, err)
rtpSender, err := stackA.api.NewRTPSender(track, stackA.dtls)
assert.NoError(t, err)
assert.Error(t, rtpSender.SetReadDeadline(time.Time{}), errRTPSenderSendNotCalled)
assert.NoError(t, stackA.close())
assert.NoError(t, stackB.close())
} }