udp_mux_universal_test.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. //go:build !js
  4. // +build !js
  5. package ice
  6. import (
  7. "net"
  8. "sync"
  9. "testing"
  10. "time"
  11. "github.com/pion/stun"
  12. "github.com/stretchr/testify/require"
  13. )
  14. func TestUniversalUDPMux(t *testing.T) {
  15. conn, err := net.ListenUDP(udp, &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1)})
  16. require.NoError(t, err)
  17. udpMux := NewUniversalUDPMuxDefault(UniversalUDPMuxParams{
  18. Logger: nil,
  19. UDPConn: conn,
  20. })
  21. defer func() {
  22. _ = udpMux.Close()
  23. _ = conn.Close()
  24. }()
  25. require.NotNil(t, udpMux.LocalAddr(), "tcpMux.LocalAddr() is nil")
  26. wg := sync.WaitGroup{}
  27. wg.Add(1)
  28. go func() {
  29. defer wg.Done()
  30. testMuxSrflxConnection(t, udpMux, "ufrag4", udp)
  31. }()
  32. wg.Wait()
  33. }
  34. func testMuxSrflxConnection(t *testing.T, udpMux *UniversalUDPMuxDefault, ufrag string, network string) {
  35. pktConn, err := udpMux.GetConn(ufrag, udpMux.LocalAddr())
  36. require.NoError(t, err, "error retrieving muxed connection for ufrag")
  37. defer func() {
  38. _ = pktConn.Close()
  39. }()
  40. remoteConn, err := net.DialUDP(network, nil, &net.UDPAddr{
  41. Port: udpMux.LocalAddr().(*net.UDPAddr).Port,
  42. })
  43. require.NoError(t, err, "error dialing test UDP connection")
  44. defer func() {
  45. _ = remoteConn.Close()
  46. }()
  47. // Use small value for TTL to check expiration of the address
  48. udpMux.params.XORMappedAddrCacheTTL = time.Millisecond * 20
  49. testXORIP := net.ParseIP("213.141.156.236")
  50. testXORPort := 21254
  51. wg := sync.WaitGroup{}
  52. wg.Add(1)
  53. go func() {
  54. defer wg.Done()
  55. address, e := udpMux.GetXORMappedAddr(remoteConn.LocalAddr(), time.Second)
  56. require.NoError(t, e)
  57. require.NotNil(t, address)
  58. require.True(t, address.IP.Equal(testXORIP))
  59. require.Equal(t, address.Port, testXORPort)
  60. }()
  61. // Wait until GetXORMappedAddr calls sendSTUN method
  62. time.Sleep(time.Millisecond)
  63. // Check that mapped address filled correctly after sent STUN
  64. udpMux.mu.Lock()
  65. mappedAddr, ok := udpMux.xorMappedMap[remoteConn.LocalAddr().String()]
  66. require.True(t, ok)
  67. require.NotNil(t, mappedAddr)
  68. require.True(t, mappedAddr.pending())
  69. require.False(t, mappedAddr.expired())
  70. udpMux.mu.Unlock()
  71. // Clean receiver read buffer
  72. buf := make([]byte, receiveMTU)
  73. _, err = remoteConn.Read(buf)
  74. require.NoError(t, err)
  75. // Write back to udpMux XOR message with address
  76. msg := stun.New()
  77. msg.Type = stun.MessageType{Method: stun.MethodBinding, Class: stun.ClassRequest}
  78. msg.Add(stun.AttrUsername, []byte(ufrag+":otherufrag"))
  79. addr := &stun.XORMappedAddress{
  80. IP: testXORIP,
  81. Port: testXORPort,
  82. }
  83. err = addr.AddTo(msg)
  84. require.NoError(t, err)
  85. msg.Encode()
  86. _, err = remoteConn.Write(msg.Raw)
  87. require.NoError(t, err)
  88. // Wait for the packet to be consumed and parsed by udpMux
  89. wg.Wait()
  90. // We should get address immediately from the cached map
  91. address, err := udpMux.GetXORMappedAddr(remoteConn.LocalAddr(), time.Second)
  92. require.NoError(t, err)
  93. require.NotNil(t, address)
  94. udpMux.mu.Lock()
  95. // Check mappedAddr is not pending, we didn't send STUN twice
  96. require.False(t, mappedAddr.pending())
  97. // Check expiration by TTL
  98. time.Sleep(time.Millisecond * 21)
  99. require.True(t, mappedAddr.expired())
  100. udpMux.mu.Unlock()
  101. // After expire, we send STUN request again
  102. // but we not receive response in 5 milliseconds and should get error here
  103. address, err = udpMux.GetXORMappedAddr(remoteConn.LocalAddr(), time.Millisecond*5)
  104. require.NotNil(t, err)
  105. require.Nil(t, address)
  106. }