github.com/pion/webrtc/v4@v4.0.1/settingengine_test.go (about)

     1  // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
     2  // SPDX-License-Identifier: MIT
     3  
     4  //go:build !js
     5  // +build !js
     6  
     7  package webrtc
     8  
     9  import (
    10  	"context"
    11  	"net"
    12  	"testing"
    13  	"time"
    14  
    15  	"github.com/pion/dtls/v3/pkg/crypto/elliptic"
    16  	"github.com/pion/dtls/v3/pkg/protocol/handshake"
    17  	"github.com/pion/ice/v4"
    18  	"github.com/pion/stun/v3"
    19  	"github.com/pion/transport/v3/test"
    20  	"github.com/stretchr/testify/assert"
    21  )
    22  
    23  func TestSetEphemeralUDPPortRange(t *testing.T) {
    24  	s := SettingEngine{}
    25  
    26  	if s.ephemeralUDP.PortMin != 0 ||
    27  		s.ephemeralUDP.PortMax != 0 {
    28  		t.Fatalf("SettingEngine defaults aren't as expected.")
    29  	}
    30  
    31  	// set bad ephemeral ports
    32  	if err := s.SetEphemeralUDPPortRange(3000, 2999); err == nil {
    33  		t.Fatalf("Setting engine should fail bad ephemeral ports.")
    34  	}
    35  
    36  	if err := s.SetEphemeralUDPPortRange(3000, 4000); err != nil {
    37  		t.Fatalf("Setting engine failed valid port range: %s", err)
    38  	}
    39  
    40  	if s.ephemeralUDP.PortMin != 3000 ||
    41  		s.ephemeralUDP.PortMax != 4000 {
    42  		t.Fatalf("Setting engine ports do not reflect expected range")
    43  	}
    44  }
    45  
    46  func TestSetConnectionTimeout(t *testing.T) {
    47  	s := SettingEngine{}
    48  
    49  	var nilDuration *time.Duration
    50  	assert.Equal(t, s.timeout.ICEDisconnectedTimeout, nilDuration)
    51  	assert.Equal(t, s.timeout.ICEFailedTimeout, nilDuration)
    52  	assert.Equal(t, s.timeout.ICEKeepaliveInterval, nilDuration)
    53  
    54  	s.SetICETimeouts(1*time.Second, 2*time.Second, 3*time.Second)
    55  	assert.Equal(t, *s.timeout.ICEDisconnectedTimeout, 1*time.Second)
    56  	assert.Equal(t, *s.timeout.ICEFailedTimeout, 2*time.Second)
    57  	assert.Equal(t, *s.timeout.ICEKeepaliveInterval, 3*time.Second)
    58  }
    59  
    60  func TestDetachDataChannels(t *testing.T) {
    61  	s := SettingEngine{}
    62  
    63  	if s.detach.DataChannels {
    64  		t.Fatalf("SettingEngine defaults aren't as expected.")
    65  	}
    66  
    67  	s.DetachDataChannels()
    68  
    69  	if !s.detach.DataChannels {
    70  		t.Fatalf("Failed to enable detached data channels.")
    71  	}
    72  }
    73  
    74  func TestSetNAT1To1IPs(t *testing.T) {
    75  	s := SettingEngine{}
    76  	if s.candidates.NAT1To1IPs != nil {
    77  		t.Errorf("Invalid default value")
    78  	}
    79  	if s.candidates.NAT1To1IPCandidateType != 0 {
    80  		t.Errorf("Invalid default value")
    81  	}
    82  
    83  	ips := []string{"1.2.3.4"}
    84  	typ := ICECandidateTypeHost
    85  	s.SetNAT1To1IPs(ips, typ)
    86  	if len(s.candidates.NAT1To1IPs) != 1 || s.candidates.NAT1To1IPs[0] != "1.2.3.4" {
    87  		t.Fatalf("Failed to set NAT1To1IPs")
    88  	}
    89  	if s.candidates.NAT1To1IPCandidateType != typ {
    90  		t.Fatalf("Failed to set NAT1To1IPCandidateType")
    91  	}
    92  }
    93  
    94  func TestSetAnsweringDTLSRole(t *testing.T) {
    95  	s := SettingEngine{}
    96  	assert.Error(t, s.SetAnsweringDTLSRole(DTLSRoleAuto), "SetAnsweringDTLSRole can only be called with DTLSRoleClient or DTLSRoleServer")
    97  	assert.Error(t, s.SetAnsweringDTLSRole(DTLSRole(0)), "SetAnsweringDTLSRole can only be called with DTLSRoleClient or DTLSRoleServer")
    98  }
    99  
   100  func TestSetReplayProtection(t *testing.T) {
   101  	s := SettingEngine{}
   102  
   103  	if s.replayProtection.DTLS != nil ||
   104  		s.replayProtection.SRTP != nil ||
   105  		s.replayProtection.SRTCP != nil {
   106  		t.Fatalf("SettingEngine defaults aren't as expected.")
   107  	}
   108  
   109  	s.SetDTLSReplayProtectionWindow(128)
   110  	s.SetSRTPReplayProtectionWindow(64)
   111  	s.SetSRTCPReplayProtectionWindow(32)
   112  
   113  	if s.replayProtection.DTLS == nil ||
   114  		*s.replayProtection.DTLS != 128 {
   115  		t.Errorf("Failed to set DTLS replay protection window")
   116  	}
   117  	if s.replayProtection.SRTP == nil ||
   118  		*s.replayProtection.SRTP != 64 {
   119  		t.Errorf("Failed to set SRTP replay protection window")
   120  	}
   121  	if s.replayProtection.SRTCP == nil ||
   122  		*s.replayProtection.SRTCP != 32 {
   123  		t.Errorf("Failed to set SRTCP replay protection window")
   124  	}
   125  }
   126  
   127  func TestSettingEngine_SetICETCP(t *testing.T) {
   128  	report := test.CheckRoutines(t)
   129  	defer report()
   130  
   131  	listener, err := net.ListenTCP("tcp", &net.TCPAddr{})
   132  	if err != nil {
   133  		panic(err)
   134  	}
   135  
   136  	defer func() {
   137  		_ = listener.Close()
   138  	}()
   139  
   140  	tcpMux := NewICETCPMux(nil, listener, 8)
   141  
   142  	defer func() {
   143  		_ = tcpMux.Close()
   144  	}()
   145  
   146  	settingEngine := SettingEngine{}
   147  	settingEngine.SetICETCPMux(tcpMux)
   148  
   149  	assert.Equal(t, tcpMux, settingEngine.iceTCPMux)
   150  }
   151  
   152  func TestSettingEngine_SetDisableMediaEngineCopy(t *testing.T) {
   153  	t.Run("Copy", func(t *testing.T) {
   154  		m := &MediaEngine{}
   155  		assert.NoError(t, m.RegisterDefaultCodecs())
   156  
   157  		api := NewAPI(WithMediaEngine(m))
   158  
   159  		offerer, answerer, err := api.newPair(Configuration{})
   160  		assert.NoError(t, err)
   161  
   162  		_, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
   163  		assert.NoError(t, err)
   164  
   165  		assert.NoError(t, signalPair(offerer, answerer))
   166  
   167  		// Assert that the MediaEngine the user created isn't modified
   168  		assert.False(t, m.negotiatedVideo)
   169  		assert.Empty(t, m.negotiatedVideoCodecs)
   170  
   171  		// Assert that the internal MediaEngine is modified
   172  		assert.True(t, offerer.api.mediaEngine.negotiatedVideo)
   173  		assert.NotEmpty(t, offerer.api.mediaEngine.negotiatedVideoCodecs)
   174  
   175  		closePairNow(t, offerer, answerer)
   176  
   177  		newOfferer, newAnswerer, err := api.newPair(Configuration{})
   178  		assert.NoError(t, err)
   179  
   180  		// Assert that the first internal MediaEngine hasn't been cleared
   181  		assert.True(t, offerer.api.mediaEngine.negotiatedVideo)
   182  		assert.NotEmpty(t, offerer.api.mediaEngine.negotiatedVideoCodecs)
   183  
   184  		// Assert that the new internal MediaEngine isn't modified
   185  		assert.False(t, newOfferer.api.mediaEngine.negotiatedVideo)
   186  		assert.Empty(t, newAnswerer.api.mediaEngine.negotiatedVideoCodecs)
   187  
   188  		closePairNow(t, newOfferer, newAnswerer)
   189  	})
   190  
   191  	t.Run("No Copy", func(t *testing.T) {
   192  		m := &MediaEngine{}
   193  		assert.NoError(t, m.RegisterDefaultCodecs())
   194  
   195  		s := SettingEngine{}
   196  		s.DisableMediaEngineCopy(true)
   197  
   198  		api := NewAPI(WithMediaEngine(m), WithSettingEngine(s))
   199  
   200  		offerer, answerer, err := api.newPair(Configuration{})
   201  		assert.NoError(t, err)
   202  
   203  		_, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
   204  		assert.NoError(t, err)
   205  
   206  		assert.NoError(t, signalPair(offerer, answerer))
   207  
   208  		// Assert that the user MediaEngine was modified, so no copy happened
   209  		assert.True(t, m.negotiatedVideo)
   210  		assert.NotEmpty(t, m.negotiatedVideoCodecs)
   211  
   212  		closePairNow(t, offerer, answerer)
   213  
   214  		offerer, answerer, err = api.newPair(Configuration{})
   215  		assert.NoError(t, err)
   216  
   217  		// Assert that the new internal MediaEngine was modified, so no copy happened
   218  		assert.True(t, offerer.api.mediaEngine.negotiatedVideo)
   219  		assert.NotEmpty(t, offerer.api.mediaEngine.negotiatedVideoCodecs)
   220  
   221  		closePairNow(t, offerer, answerer)
   222  	})
   223  }
   224  
   225  func TestSetDTLSRetransmissionInterval(t *testing.T) {
   226  	s := SettingEngine{}
   227  
   228  	if s.dtls.retransmissionInterval != 0 {
   229  		t.Fatalf("SettingEngine defaults aren't as expected.")
   230  	}
   231  
   232  	s.SetDTLSRetransmissionInterval(100 * time.Millisecond)
   233  	if s.dtls.retransmissionInterval == 0 ||
   234  		s.dtls.retransmissionInterval != 100*time.Millisecond {
   235  		t.Errorf("Failed to set DTLS retransmission interval")
   236  	}
   237  
   238  	s.SetDTLSRetransmissionInterval(1 * time.Second)
   239  	if s.dtls.retransmissionInterval == 0 ||
   240  		s.dtls.retransmissionInterval != 1*time.Second {
   241  		t.Errorf("Failed to set DTLS retransmission interval")
   242  	}
   243  }
   244  
   245  func TestSetDTLSEllipticCurves(t *testing.T) {
   246  	s := SettingEngine{}
   247  
   248  	if len(s.dtls.ellipticCurves) != 0 {
   249  		t.Fatalf("SettingEngine defaults aren't as expected.")
   250  	}
   251  
   252  	s.SetDTLSEllipticCurves(elliptic.P256)
   253  	if len(s.dtls.ellipticCurves) == 0 ||
   254  		s.dtls.ellipticCurves[0] != elliptic.P256 {
   255  		t.Errorf("Failed to set DTLS elliptic curves")
   256  	}
   257  }
   258  
   259  func TestSetDTLSHandShakeTimeout(*testing.T) {
   260  	s := SettingEngine{}
   261  
   262  	s.SetDTLSConnectContextMaker(func() (context.Context, func()) {
   263  		return context.WithTimeout(context.Background(), 60*time.Second)
   264  	})
   265  }
   266  
   267  func TestSetSCTPMaxReceiverBufferSize(t *testing.T) {
   268  	s := SettingEngine{}
   269  	assert.Equal(t, uint32(0), s.sctp.maxReceiveBufferSize)
   270  
   271  	expSize := uint32(4 * 1024 * 1024)
   272  	s.SetSCTPMaxReceiveBufferSize(expSize)
   273  	assert.Equal(t, expSize, s.sctp.maxReceiveBufferSize)
   274  }
   275  
   276  func TestSetSCTPRTOMax(t *testing.T) {
   277  	s := SettingEngine{}
   278  	assert.Equal(t, time.Duration(0), s.sctp.rtoMax)
   279  
   280  	expSize := time.Second
   281  	s.SetSCTPRTOMax(expSize)
   282  	assert.Equal(t, expSize, s.sctp.rtoMax)
   283  }
   284  
   285  func TestSetICEBindingRequestHandler(t *testing.T) {
   286  	seenICEControlled, seenICEControlledCancel := context.WithCancel(context.Background())
   287  	seenICEControlling, seenICEControllingCancel := context.WithCancel(context.Background())
   288  
   289  	s := SettingEngine{}
   290  	s.SetICEBindingRequestHandler(func(m *stun.Message, _, _ ice.Candidate, _ *ice.CandidatePair) bool {
   291  		for _, a := range m.Attributes {
   292  			switch a.Type {
   293  			case stun.AttrICEControlled:
   294  				seenICEControlledCancel()
   295  			case stun.AttrICEControlling:
   296  				seenICEControllingCancel()
   297  			default:
   298  			}
   299  		}
   300  
   301  		return false
   302  	})
   303  
   304  	pcOffer, pcAnswer, err := NewAPI(WithSettingEngine(s)).newPair(Configuration{})
   305  	assert.NoError(t, err)
   306  
   307  	assert.NoError(t, signalPair(pcOffer, pcAnswer))
   308  
   309  	<-seenICEControlled.Done()
   310  	<-seenICEControlling.Done()
   311  	closePairNow(t, pcOffer, pcAnswer)
   312  }
   313  
   314  func TestSetHooks(t *testing.T) {
   315  	s := SettingEngine{}
   316  
   317  	if s.dtls.clientHelloMessageHook != nil ||
   318  		s.dtls.serverHelloMessageHook != nil ||
   319  		s.dtls.certificateRequestMessageHook != nil {
   320  		t.Fatalf("SettingEngine defaults aren't as expected.")
   321  	}
   322  
   323  	s.SetDTLSClientHelloMessageHook(func(msg handshake.MessageClientHello) handshake.Message {
   324  		return &msg
   325  	})
   326  	s.SetDTLSServerHelloMessageHook(func(msg handshake.MessageServerHello) handshake.Message {
   327  		return &msg
   328  	})
   329  	s.SetDTLSCertificateRequestMessageHook(func(msg handshake.MessageCertificateRequest) handshake.Message {
   330  		return &msg
   331  	})
   332  
   333  	if s.dtls.clientHelloMessageHook == nil {
   334  		t.Errorf("Failed to set DTLS Client Hello Hook")
   335  	}
   336  	if s.dtls.serverHelloMessageHook == nil {
   337  		t.Errorf("Failed to set DTLS Server Hello Hook")
   338  	}
   339  	if s.dtls.certificateRequestMessageHook == nil {
   340  		t.Errorf("Failed to set DTLS Certificate Request Hook")
   341  	}
   342  }
   343  
   344  func TestSetFireOnTrackBeforeFirstRTP(t *testing.T) {
   345  	lim := test.TimeOut(time.Second * 30)
   346  	defer lim.Stop()
   347  
   348  	report := test.CheckRoutines(t)
   349  	defer report()
   350  
   351  	s := SettingEngine{}
   352  	s.SetFireOnTrackBeforeFirstRTP(true)
   353  
   354  	mediaEngineOne := &MediaEngine{}
   355  	assert.NoError(t, mediaEngineOne.RegisterCodec(RTPCodecParameters{
   356  		RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
   357  		PayloadType:        100,
   358  	}, RTPCodecTypeVideo))
   359  
   360  	mediaEngineTwo := &MediaEngine{}
   361  	assert.NoError(t, mediaEngineTwo.RegisterCodec(RTPCodecParameters{
   362  		RTPCodecCapability: RTPCodecCapability{MimeType: "video/VP8", ClockRate: 90000, Channels: 0, SDPFmtpLine: "", RTCPFeedback: nil},
   363  		PayloadType:        200,
   364  	}, RTPCodecTypeVideo))
   365  
   366  	offerer, err := NewAPI(WithMediaEngine(mediaEngineOne), WithSettingEngine(s)).NewPeerConnection(Configuration{})
   367  	assert.NoError(t, err)
   368  
   369  	answerer, err := NewAPI(WithMediaEngine(mediaEngineTwo)).NewPeerConnection(Configuration{})
   370  	assert.NoError(t, err)
   371  
   372  	track, err := NewTrackLocalStaticSample(RTPCodecCapability{MimeType: MimeTypeVP8}, "video", "pion")
   373  	assert.NoError(t, err)
   374  
   375  	_, err = offerer.AddTransceiverFromKind(RTPCodecTypeVideo)
   376  	assert.NoError(t, err)
   377  
   378  	_, err = answerer.AddTrack(track)
   379  	assert.NoError(t, err)
   380  
   381  	onTrackFired, onTrackFiredFunc := context.WithCancel(context.Background())
   382  	offerer.OnTrack(func(track *TrackRemote, _ *RTPReceiver) {
   383  		_, _, err = track.Read(make([]byte, 1500))
   384  		assert.NoError(t, err)
   385  		assert.Equal(t, track.PayloadType(), PayloadType(100))
   386  		assert.Equal(t, track.Codec().RTPCodecCapability.MimeType, "video/VP8")
   387  
   388  		onTrackFiredFunc()
   389  	})
   390  
   391  	assert.NoError(t, signalPair(offerer, answerer))
   392  
   393  	sendVideoUntilDone(onTrackFired.Done(), t, []*TrackLocalStaticSample{track})
   394  
   395  	closePairNow(t, offerer, answerer)
   396  }