candidate_test.go 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package ice
  4. import (
  5. "net"
  6. "testing"
  7. "time"
  8. "github.com/pion/logging"
  9. "github.com/stretchr/testify/assert"
  10. "github.com/stretchr/testify/require"
  11. )
  12. func TestCandidateTypePreference(t *testing.T) {
  13. r := require.New(t)
  14. hostDefaultPreference := uint16(126)
  15. prflxDefaultPreference := uint16(110)
  16. srflxDefaultPreference := uint16(100)
  17. relayDefaultPreference := uint16(0)
  18. tcpOffsets := []uint16{0, 10}
  19. for _, tcpOffset := range tcpOffsets {
  20. agent := &Agent{
  21. tcpPriorityOffset: tcpOffset,
  22. }
  23. for _, networkType := range supportedNetworkTypes() {
  24. hostCandidate := candidateBase{
  25. candidateType: CandidateTypeHost,
  26. networkType: networkType,
  27. currAgent: agent,
  28. }
  29. prflxCandidate := candidateBase{
  30. candidateType: CandidateTypePeerReflexive,
  31. networkType: networkType,
  32. currAgent: agent,
  33. }
  34. srflxCandidate := candidateBase{
  35. candidateType: CandidateTypeServerReflexive,
  36. networkType: networkType,
  37. currAgent: agent,
  38. }
  39. relayCandidate := candidateBase{
  40. candidateType: CandidateTypeRelay,
  41. networkType: networkType,
  42. currAgent: agent,
  43. }
  44. if networkType.IsTCP() {
  45. r.Equal(hostDefaultPreference-tcpOffset, hostCandidate.TypePreference())
  46. r.Equal(prflxDefaultPreference-tcpOffset, prflxCandidate.TypePreference())
  47. r.Equal(srflxDefaultPreference-tcpOffset, srflxCandidate.TypePreference())
  48. } else {
  49. r.Equal(hostDefaultPreference, hostCandidate.TypePreference())
  50. r.Equal(prflxDefaultPreference, prflxCandidate.TypePreference())
  51. r.Equal(srflxDefaultPreference, srflxCandidate.TypePreference())
  52. }
  53. r.Equal(relayDefaultPreference, relayCandidate.TypePreference())
  54. }
  55. }
  56. }
  57. func TestCandidatePriority(t *testing.T) {
  58. for _, test := range []struct {
  59. Candidate Candidate
  60. WantPriority uint32
  61. }{
  62. {
  63. Candidate: &CandidateHost{
  64. candidateBase: candidateBase{
  65. candidateType: CandidateTypeHost,
  66. component: ComponentRTP,
  67. },
  68. },
  69. WantPriority: 2130706431,
  70. },
  71. {
  72. Candidate: &CandidateHost{
  73. candidateBase: candidateBase{
  74. candidateType: CandidateTypeHost,
  75. component: ComponentRTP,
  76. networkType: NetworkTypeTCP4,
  77. tcpType: TCPTypeActive,
  78. },
  79. },
  80. WantPriority: 1675624447,
  81. },
  82. {
  83. Candidate: &CandidateHost{
  84. candidateBase: candidateBase{
  85. candidateType: CandidateTypeHost,
  86. component: ComponentRTP,
  87. networkType: NetworkTypeTCP4,
  88. tcpType: TCPTypePassive,
  89. },
  90. },
  91. WantPriority: 1671430143,
  92. },
  93. {
  94. Candidate: &CandidateHost{
  95. candidateBase: candidateBase{
  96. candidateType: CandidateTypeHost,
  97. component: ComponentRTP,
  98. networkType: NetworkTypeTCP4,
  99. tcpType: TCPTypeSimultaneousOpen,
  100. },
  101. },
  102. WantPriority: 1667235839,
  103. },
  104. {
  105. Candidate: &CandidatePeerReflexive{
  106. candidateBase: candidateBase{
  107. candidateType: CandidateTypePeerReflexive,
  108. component: ComponentRTP,
  109. },
  110. },
  111. WantPriority: 1862270975,
  112. },
  113. {
  114. Candidate: &CandidatePeerReflexive{
  115. candidateBase: candidateBase{
  116. candidateType: CandidateTypePeerReflexive,
  117. component: ComponentRTP,
  118. networkType: NetworkTypeTCP6,
  119. tcpType: TCPTypeSimultaneousOpen,
  120. },
  121. },
  122. WantPriority: 1407188991,
  123. },
  124. {
  125. Candidate: &CandidatePeerReflexive{
  126. candidateBase: candidateBase{
  127. candidateType: CandidateTypePeerReflexive,
  128. component: ComponentRTP,
  129. networkType: NetworkTypeTCP6,
  130. tcpType: TCPTypeActive,
  131. },
  132. },
  133. WantPriority: 1402994687,
  134. },
  135. {
  136. Candidate: &CandidatePeerReflexive{
  137. candidateBase: candidateBase{
  138. candidateType: CandidateTypePeerReflexive,
  139. component: ComponentRTP,
  140. networkType: NetworkTypeTCP6,
  141. tcpType: TCPTypePassive,
  142. },
  143. },
  144. WantPriority: 1398800383,
  145. },
  146. {
  147. Candidate: &CandidateServerReflexive{
  148. candidateBase: candidateBase{
  149. candidateType: CandidateTypeServerReflexive,
  150. component: ComponentRTP,
  151. },
  152. },
  153. WantPriority: 1694498815,
  154. },
  155. {
  156. Candidate: &CandidateRelay{
  157. candidateBase: candidateBase{
  158. candidateType: CandidateTypeRelay,
  159. component: ComponentRTP,
  160. },
  161. },
  162. WantPriority: 16777215,
  163. },
  164. } {
  165. if got, want := test.Candidate.Priority(), test.WantPriority; got != want {
  166. t.Fatalf("Candidate(%v).Priority() = %d, want %d", test.Candidate, got, want)
  167. }
  168. }
  169. }
  170. func TestCandidateLastSent(t *testing.T) {
  171. candidate := candidateBase{}
  172. assert.Equal(t, candidate.LastSent(), time.Time{})
  173. now := time.Now()
  174. candidate.setLastSent(now)
  175. assert.EqualValues(t, 0, now.Sub(candidate.LastSent()))
  176. }
  177. func TestCandidateLastReceived(t *testing.T) {
  178. candidate := candidateBase{}
  179. assert.Equal(t, candidate.LastReceived(), time.Time{})
  180. now := time.Now()
  181. candidate.setLastReceived(now)
  182. assert.EqualValues(t, 0, now.Sub(candidate.LastReceived()))
  183. }
  184. func TestCandidateFoundation(t *testing.T) {
  185. // All fields are the same
  186. assert.Equal(t,
  187. (&candidateBase{
  188. candidateType: CandidateTypeHost,
  189. networkType: NetworkTypeUDP4,
  190. address: "A",
  191. }).Foundation(),
  192. (&candidateBase{
  193. candidateType: CandidateTypeHost,
  194. networkType: NetworkTypeUDP4,
  195. address: "A",
  196. }).Foundation())
  197. // Different Address
  198. assert.NotEqual(t,
  199. (&candidateBase{
  200. candidateType: CandidateTypeHost,
  201. networkType: NetworkTypeUDP4,
  202. address: "A",
  203. }).Foundation(),
  204. (&candidateBase{
  205. candidateType: CandidateTypeHost,
  206. networkType: NetworkTypeUDP4,
  207. address: "B",
  208. }).Foundation())
  209. // Different networkType
  210. assert.NotEqual(t,
  211. (&candidateBase{
  212. candidateType: CandidateTypeHost,
  213. networkType: NetworkTypeUDP4,
  214. address: "A",
  215. }).Foundation(),
  216. (&candidateBase{
  217. candidateType: CandidateTypeHost,
  218. networkType: NetworkTypeUDP6,
  219. address: "A",
  220. }).Foundation())
  221. // Different candidateType
  222. assert.NotEqual(t,
  223. (&candidateBase{
  224. candidateType: CandidateTypeHost,
  225. networkType: NetworkTypeUDP4,
  226. address: "A",
  227. }).Foundation(),
  228. (&candidateBase{
  229. candidateType: CandidateTypePeerReflexive,
  230. networkType: NetworkTypeUDP4,
  231. address: "A",
  232. }).Foundation())
  233. // Port has no effect
  234. assert.Equal(t,
  235. (&candidateBase{
  236. candidateType: CandidateTypeHost,
  237. networkType: NetworkTypeUDP4,
  238. address: "A",
  239. port: 8080,
  240. }).Foundation(),
  241. (&candidateBase{
  242. candidateType: CandidateTypeHost,
  243. networkType: NetworkTypeUDP4,
  244. address: "A",
  245. port: 80,
  246. }).Foundation())
  247. }
  248. func TestCandidateMarshal(t *testing.T) {
  249. for _, test := range []struct {
  250. candidate Candidate
  251. marshaled string
  252. expectError bool
  253. }{
  254. {
  255. &CandidateHost{
  256. candidateBase{
  257. networkType: NetworkTypeUDP6,
  258. candidateType: CandidateTypeHost,
  259. address: "fcd9:e3b8:12ce:9fc5:74a5:c6bb:d8b:e08a",
  260. port: 53987,
  261. priorityOverride: 500,
  262. foundationOverride: "750",
  263. },
  264. "",
  265. },
  266. "750 1 udp 500 fcd9:e3b8:12ce:9fc5:74a5:c6bb:d8b:e08a 53987 typ host",
  267. false,
  268. },
  269. {
  270. &CandidateHost{
  271. candidateBase{
  272. networkType: NetworkTypeUDP4,
  273. candidateType: CandidateTypeHost,
  274. address: "10.0.75.1",
  275. port: 53634,
  276. },
  277. "",
  278. },
  279. "4273957277 1 udp 2130706431 10.0.75.1 53634 typ host",
  280. false,
  281. },
  282. {
  283. &CandidateServerReflexive{
  284. candidateBase{
  285. networkType: NetworkTypeUDP4,
  286. candidateType: CandidateTypeServerReflexive,
  287. address: "191.228.238.68",
  288. port: 53991,
  289. relatedAddress: &CandidateRelatedAddress{"192.168.0.274", 53991},
  290. },
  291. },
  292. "647372371 1 udp 1694498815 191.228.238.68 53991 typ srflx raddr 192.168.0.274 rport 53991",
  293. false,
  294. },
  295. {
  296. &CandidateRelay{
  297. candidateBase{
  298. networkType: NetworkTypeUDP4,
  299. candidateType: CandidateTypeRelay,
  300. address: "50.0.0.1",
  301. port: 5000,
  302. relatedAddress: &CandidateRelatedAddress{"192.168.0.1", 5001},
  303. },
  304. "",
  305. nil,
  306. },
  307. "848194626 1 udp 16777215 50.0.0.1 5000 typ relay raddr 192.168.0.1 rport 5001",
  308. false,
  309. },
  310. {
  311. &CandidateHost{
  312. candidateBase{
  313. networkType: NetworkTypeTCP4,
  314. candidateType: CandidateTypeHost,
  315. address: "192.168.0.196",
  316. port: 0,
  317. tcpType: TCPTypeActive,
  318. },
  319. "",
  320. },
  321. "1052353102 1 tcp 2128609279 192.168.0.196 0 typ host tcptype active",
  322. false,
  323. },
  324. {
  325. &CandidateHost{
  326. candidateBase{
  327. networkType: NetworkTypeUDP4,
  328. candidateType: CandidateTypeHost,
  329. address: "e2494022-4d9a-4c1e-a750-cc48d4f8d6ee.local",
  330. port: 60542,
  331. },
  332. "",
  333. },
  334. "1380287402 1 udp 2130706431 e2494022-4d9a-4c1e-a750-cc48d4f8d6ee.local 60542 typ host", false,
  335. },
  336. // Missing Foundation
  337. {
  338. &CandidateHost{
  339. candidateBase{
  340. networkType: NetworkTypeUDP4,
  341. candidateType: CandidateTypeHost,
  342. address: "127.0.0.1",
  343. port: 80,
  344. priorityOverride: 500,
  345. foundationOverride: " ",
  346. },
  347. "",
  348. },
  349. " 1 udp 500 127.0.0.1 80 typ host",
  350. false,
  351. },
  352. // Invalid candidates
  353. {nil, "", true},
  354. {nil, "1938809241", true},
  355. {nil, "1986380506 99999999 udp 2122063615 10.0.75.1 53634 typ host generation 0 network-id 2", true},
  356. {nil, "1986380506 1 udp 99999999999 10.0.75.1 53634 typ host", true},
  357. {nil, "4207374051 1 udp 1685790463 191.228.238.68 99999999 typ srflx raddr 192.168.0.278 rport 53991 generation 0 network-id 3", true},
  358. {nil, "4207374051 1 udp 1685790463 191.228.238.68 53991 typ srflx raddr", true},
  359. {nil, "4207374051 1 udp 1685790463 191.228.238.68 53991 typ srflx raddr 192.168.0.278 rport 99999999 generation 0 network-id 3", true},
  360. {nil, "4207374051 INVALID udp 2130706431 10.0.75.1 53634 typ host", true},
  361. {nil, "4207374051 1 udp INVALID 10.0.75.1 53634 typ host", true},
  362. {nil, "4207374051 INVALID udp 2130706431 10.0.75.1 INVALID typ host", true},
  363. {nil, "4207374051 1 udp 2130706431 10.0.75.1 53634 typ INVALID", true},
  364. {nil, "4207374051 1 INVALID 2130706431 10.0.75.1 53634 typ host", true},
  365. } {
  366. actualCandidate, err := UnmarshalCandidate(test.marshaled)
  367. if test.expectError {
  368. assert.Error(t, err)
  369. continue
  370. }
  371. assert.NoError(t, err)
  372. assert.True(t, test.candidate.Equal(actualCandidate))
  373. assert.Equal(t, test.marshaled, actualCandidate.Marshal())
  374. }
  375. }
  376. func TestCandidateWriteTo(t *testing.T) {
  377. listener, err := net.ListenTCP("tcp", &net.TCPAddr{
  378. IP: net.IP{127, 0, 0, 1},
  379. Port: 0,
  380. })
  381. require.NoError(t, err, "error creating test TCP listener")
  382. conn, err := net.DialTCP("tcp", nil, listener.Addr().(*net.TCPAddr))
  383. require.NoError(t, err, "error dialing test TCP connection")
  384. loggerFactory := logging.NewDefaultLoggerFactory()
  385. packetConn := newTCPPacketConn(tcpPacketParams{
  386. ReadBuffer: 2048,
  387. Logger: loggerFactory.NewLogger("tcp-packet-conn"),
  388. })
  389. err = packetConn.AddConn(conn, nil)
  390. require.NoError(t, err, "error adding test TCP connection to packet connection")
  391. c1 := &candidateBase{
  392. conn: packetConn,
  393. currAgent: &Agent{
  394. log: loggerFactory.NewLogger("agent"),
  395. },
  396. }
  397. c2 := &candidateBase{
  398. resolvedAddr: listener.Addr(),
  399. }
  400. _, err = c1.writeTo([]byte("test"), c2)
  401. assert.NoError(t, err, "writing to open conn")
  402. err = packetConn.Close()
  403. require.NoError(t, err, "error closing test TCP connection")
  404. _, err = c1.writeTo([]byte("test"), c2)
  405. assert.Error(t, err, "writing to closed conn")
  406. }