active_tcp_test.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  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. "testing"
  9. "time"
  10. "github.com/pion/logging"
  11. "github.com/pion/transport/v2/stdnet"
  12. "github.com/pion/transport/v2/test"
  13. "github.com/stretchr/testify/assert"
  14. "github.com/stretchr/testify/require"
  15. )
  16. func getLocalIPAddress(t *testing.T, networkType NetworkType) net.IP {
  17. net, err := stdnet.NewNet()
  18. require.NoError(t, err)
  19. localIPs, err := localInterfaces(net, nil, nil, []NetworkType{networkType}, false)
  20. require.NoError(t, err)
  21. require.NotEmpty(t, localIPs)
  22. return localIPs[0]
  23. }
  24. func ipv6Available(t *testing.T) bool {
  25. net, err := stdnet.NewNet()
  26. require.NoError(t, err)
  27. localIPs, err := localInterfaces(net, nil, nil, []NetworkType{NetworkTypeTCP6}, false)
  28. require.NoError(t, err)
  29. return len(localIPs) > 0
  30. }
  31. func TestActiveTCP(t *testing.T) {
  32. report := test.CheckRoutines(t)
  33. defer report()
  34. lim := test.TimeOut(time.Second * 5)
  35. defer lim.Stop()
  36. const listenPort = 7686
  37. type testCase struct {
  38. name string
  39. networkTypes []NetworkType
  40. listenIPAddress net.IP
  41. selectedPairNetworkType string
  42. }
  43. testCases := []testCase{
  44. {
  45. name: "TCP4 connection",
  46. networkTypes: []NetworkType{NetworkTypeTCP4},
  47. listenIPAddress: getLocalIPAddress(t, NetworkTypeTCP4),
  48. selectedPairNetworkType: tcp,
  49. },
  50. {
  51. name: "UDP is preferred over TCP4", // This fails some time
  52. networkTypes: supportedNetworkTypes(),
  53. listenIPAddress: getLocalIPAddress(t, NetworkTypeTCP4),
  54. selectedPairNetworkType: udp,
  55. },
  56. }
  57. if ipv6Available(t) {
  58. testCases = append(testCases,
  59. testCase{
  60. name: "TCP6 connection",
  61. networkTypes: []NetworkType{NetworkTypeTCP6},
  62. listenIPAddress: getLocalIPAddress(t, NetworkTypeTCP6),
  63. selectedPairNetworkType: tcp,
  64. },
  65. testCase{
  66. name: "UDP is preferred over TCP6", // This fails some time
  67. networkTypes: supportedNetworkTypes(),
  68. listenIPAddress: getLocalIPAddress(t, NetworkTypeTCP6),
  69. selectedPairNetworkType: udp,
  70. },
  71. )
  72. }
  73. for _, testCase := range testCases {
  74. t.Run(testCase.name, func(t *testing.T) {
  75. r := require.New(t)
  76. listener, err := net.ListenTCP("tcp", &net.TCPAddr{
  77. IP: testCase.listenIPAddress,
  78. Port: listenPort,
  79. })
  80. r.NoError(err)
  81. defer func() {
  82. _ = listener.Close()
  83. }()
  84. loggerFactory := logging.NewDefaultLoggerFactory()
  85. tcpMux := NewTCPMuxDefault(TCPMuxParams{
  86. Listener: listener,
  87. Logger: loggerFactory.NewLogger("passive-ice-tcp-mux"),
  88. ReadBufferSize: 20,
  89. })
  90. defer func() {
  91. _ = tcpMux.Close()
  92. }()
  93. r.NotNil(tcpMux.LocalAddr(), "tcpMux.LocalAddr() is nil")
  94. hostAcceptanceMinWait := 100 * time.Millisecond
  95. passiveAgent, err := NewAgent(&AgentConfig{
  96. TCPMux: tcpMux,
  97. CandidateTypes: []CandidateType{CandidateTypeHost},
  98. NetworkTypes: testCase.networkTypes,
  99. LoggerFactory: loggerFactory,
  100. IncludeLoopback: true,
  101. HostAcceptanceMinWait: &hostAcceptanceMinWait,
  102. })
  103. r.NoError(err)
  104. r.NotNil(passiveAgent)
  105. activeAgent, err := NewAgent(&AgentConfig{
  106. CandidateTypes: []CandidateType{CandidateTypeHost},
  107. NetworkTypes: testCase.networkTypes,
  108. LoggerFactory: loggerFactory,
  109. HostAcceptanceMinWait: &hostAcceptanceMinWait,
  110. })
  111. r.NoError(err)
  112. r.NotNil(activeAgent)
  113. passiveAgentConn, activeAgenConn := connect(passiveAgent, activeAgent)
  114. r.NotNil(passiveAgentConn)
  115. r.NotNil(activeAgenConn)
  116. pair := passiveAgent.getSelectedPair()
  117. r.NotNil(pair)
  118. r.Equal(testCase.selectedPairNetworkType, pair.Local.NetworkType().NetworkShort())
  119. foo := []byte("foo")
  120. _, err = passiveAgentConn.Write(foo)
  121. r.NoError(err)
  122. buffer := make([]byte, 1024)
  123. n, err := activeAgenConn.Read(buffer)
  124. r.NoError(err)
  125. r.Equal(foo, buffer[:n])
  126. bar := []byte("bar")
  127. _, err = activeAgenConn.Write(bar)
  128. r.NoError(err)
  129. n, err = passiveAgentConn.Read(buffer)
  130. r.NoError(err)
  131. r.Equal(bar, buffer[:n])
  132. r.NoError(activeAgenConn.Close())
  133. r.NoError(passiveAgentConn.Close())
  134. })
  135. }
  136. }
  137. // Assert that Active TCP connectivity isn't established inside
  138. // the main thread of the Agent
  139. func TestActiveTCP_NonBlocking(t *testing.T) {
  140. report := test.CheckRoutines(t)
  141. defer report()
  142. lim := test.TimeOut(time.Second * 5)
  143. defer lim.Stop()
  144. cfg := &AgentConfig{
  145. NetworkTypes: supportedNetworkTypes(),
  146. }
  147. aAgent, err := NewAgent(cfg)
  148. if err != nil {
  149. t.Error(err)
  150. }
  151. bAgent, err := NewAgent(cfg)
  152. if err != nil {
  153. t.Error(err)
  154. }
  155. isConnected := make(chan interface{})
  156. err = aAgent.OnConnectionStateChange(func(c ConnectionState) {
  157. if c == ConnectionStateConnected {
  158. close(isConnected)
  159. }
  160. })
  161. if err != nil {
  162. t.Error(err)
  163. }
  164. // Add a invalid ice-tcp candidate to each
  165. invalidCandidate, err := UnmarshalCandidate("1052353102 1 tcp 1675624447 192.0.2.1 8080 typ host tcptype passive")
  166. if err != nil {
  167. t.Fatal(err)
  168. }
  169. assert.NoError(t, aAgent.AddRemoteCandidate(invalidCandidate))
  170. assert.NoError(t, bAgent.AddRemoteCandidate(invalidCandidate))
  171. connect(aAgent, bAgent)
  172. <-isConnected
  173. assert.NoError(t, aAgent.Close())
  174. assert.NoError(t, bAgent.Close())
  175. }