candidate_base.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509
  1. package ice
  2. import (
  3. "context"
  4. "fmt"
  5. "hash/crc32"
  6. "net"
  7. "strconv"
  8. "strings"
  9. "sync/atomic"
  10. "time"
  11. "github.com/pion/logging"
  12. "github.com/pion/stun"
  13. )
  14. type candidateBase struct {
  15. id string
  16. networkType NetworkType
  17. candidateType CandidateType
  18. component uint16
  19. address string
  20. port int
  21. relatedAddress *CandidateRelatedAddress
  22. tcpType TCPType
  23. resolvedAddr net.Addr
  24. lastSent atomic.Value
  25. lastReceived atomic.Value
  26. conn net.PacketConn
  27. currAgent *Agent
  28. closeCh chan struct{}
  29. closedCh chan struct{}
  30. foundationOverride string
  31. priorityOverride uint32
  32. }
  33. // Done implements context.Context
  34. func (c *candidateBase) Done() <-chan struct{} {
  35. return c.closeCh
  36. }
  37. // Err implements context.Context
  38. func (c *candidateBase) Err() error {
  39. select {
  40. case <-c.closedCh:
  41. return ErrRunCanceled
  42. default:
  43. return nil
  44. }
  45. }
  46. // Deadline implements context.Context
  47. func (c *candidateBase) Deadline() (deadline time.Time, ok bool) {
  48. return time.Time{}, false
  49. }
  50. // Value implements context.Context
  51. func (c *candidateBase) Value(key interface{}) interface{} {
  52. return nil
  53. }
  54. // ID returns Candidate ID
  55. func (c *candidateBase) ID() string {
  56. return c.id
  57. }
  58. func (c *candidateBase) Foundation() string {
  59. if c.foundationOverride != "" {
  60. return c.foundationOverride
  61. }
  62. return fmt.Sprintf("%d", crc32.ChecksumIEEE([]byte(c.Type().String()+c.address+c.networkType.String())))
  63. }
  64. // Address returns Candidate Address
  65. func (c *candidateBase) Address() string {
  66. return c.address
  67. }
  68. // Port returns Candidate Port
  69. func (c *candidateBase) Port() int {
  70. return c.port
  71. }
  72. // Type returns candidate type
  73. func (c *candidateBase) Type() CandidateType {
  74. return c.candidateType
  75. }
  76. // NetworkType returns candidate NetworkType
  77. func (c *candidateBase) NetworkType() NetworkType {
  78. return c.networkType
  79. }
  80. // Component returns candidate component
  81. func (c *candidateBase) Component() uint16 {
  82. return c.component
  83. }
  84. func (c *candidateBase) SetComponent(component uint16) {
  85. c.component = component
  86. }
  87. // LocalPreference returns the local preference for this candidate
  88. func (c *candidateBase) LocalPreference() uint16 {
  89. if c.NetworkType().IsTCP() {
  90. // RFC 6544, section 4.2
  91. //
  92. // In Section 4.1.2.1 of [RFC5245], a recommended formula for UDP ICE
  93. // candidate prioritization is defined. For TCP candidates, the same
  94. // formula and candidate type preferences SHOULD be used, and the
  95. // RECOMMENDED type preferences for the new candidate types defined in
  96. // this document (see Section 5) are 105 for NAT-assisted candidates and
  97. // 75 for UDP-tunneled candidates.
  98. //
  99. // (...)
  100. //
  101. // With TCP candidates, the local preference part of the recommended
  102. // priority formula is updated to also include the directionality
  103. // (active, passive, or simultaneous-open) of the TCP connection. The
  104. // RECOMMENDED local preference is then defined as:
  105. //
  106. // local preference = (2^13) * direction-pref + other-pref
  107. //
  108. // The direction-pref MUST be between 0 and 7 (both inclusive), with 7
  109. // being the most preferred. The other-pref MUST be between 0 and 8191
  110. // (both inclusive), with 8191 being the most preferred. It is
  111. // RECOMMENDED that the host, UDP-tunneled, and relayed TCP candidates
  112. // have the direction-pref assigned as follows: 6 for active, 4 for
  113. // passive, and 2 for S-O. For the NAT-assisted and server reflexive
  114. // candidates, the RECOMMENDED values are: 6 for S-O, 4 for active, and
  115. // 2 for passive.
  116. //
  117. // (...)
  118. //
  119. // If any two candidates have the same type-preference and direction-
  120. // pref, they MUST have a unique other-pref. With this specification,
  121. // this usually only happens with multi-homed hosts, in which case
  122. // other-pref is the preference for the particular IP address from which
  123. // the candidate was obtained. When there is only a single IP address,
  124. // this value SHOULD be set to the maximum allowed value (8191).
  125. var otherPref uint16 = 8191
  126. directionPref := func() uint16 {
  127. switch c.Type() {
  128. case CandidateTypeHost, CandidateTypeRelay:
  129. switch c.tcpType {
  130. case TCPTypeActive:
  131. return 6
  132. case TCPTypePassive:
  133. return 4
  134. case TCPTypeSimultaneousOpen:
  135. return 2
  136. case TCPTypeUnspecified:
  137. return 0
  138. }
  139. case CandidateTypePeerReflexive, CandidateTypeServerReflexive:
  140. switch c.tcpType {
  141. case TCPTypeSimultaneousOpen:
  142. return 6
  143. case TCPTypeActive:
  144. return 4
  145. case TCPTypePassive:
  146. return 2
  147. case TCPTypeUnspecified:
  148. return 0
  149. }
  150. case CandidateTypeUnspecified:
  151. return 0
  152. }
  153. return 0
  154. }()
  155. return (1<<13)*directionPref + otherPref
  156. }
  157. return defaultLocalPreference
  158. }
  159. // RelatedAddress returns *CandidateRelatedAddress
  160. func (c *candidateBase) RelatedAddress() *CandidateRelatedAddress {
  161. return c.relatedAddress
  162. }
  163. func (c *candidateBase) TCPType() TCPType {
  164. return c.tcpType
  165. }
  166. // start runs the candidate using the provided connection
  167. func (c *candidateBase) start(a *Agent, conn net.PacketConn, initializedCh <-chan struct{}) {
  168. if c.conn != nil {
  169. c.agent().log.Warn("Can't start already started candidateBase")
  170. return
  171. }
  172. c.currAgent = a
  173. c.conn = conn
  174. c.closeCh = make(chan struct{})
  175. c.closedCh = make(chan struct{})
  176. go c.recvLoop(initializedCh)
  177. }
  178. func (c *candidateBase) recvLoop(initializedCh <-chan struct{}) {
  179. defer func() {
  180. close(c.closedCh)
  181. }()
  182. select {
  183. case <-initializedCh:
  184. case <-c.closeCh:
  185. return
  186. }
  187. log := c.agent().log
  188. buffer := make([]byte, receiveMTU)
  189. for {
  190. n, srcAddr, err := c.conn.ReadFrom(buffer)
  191. if err != nil {
  192. return
  193. }
  194. handleInboundCandidateMsg(c, c, buffer[:n], srcAddr, log)
  195. }
  196. }
  197. func handleInboundCandidateMsg(ctx context.Context, c Candidate, buffer []byte, srcAddr net.Addr, log logging.LeveledLogger) {
  198. if stun.IsMessage(buffer) {
  199. m := &stun.Message{
  200. Raw: make([]byte, len(buffer)),
  201. }
  202. // Explicitly copy raw buffer so Message can own the memory.
  203. copy(m.Raw, buffer)
  204. if err := m.Decode(); err != nil {
  205. log.Warnf("Failed to handle decode ICE from %s to %s: %v", c.addr(), srcAddr, err)
  206. return
  207. }
  208. err := c.agent().run(ctx, func(ctx context.Context, agent *Agent) {
  209. agent.handleInbound(m, c, srcAddr)
  210. })
  211. if err != nil {
  212. log.Warnf("Failed to handle message: %v", err)
  213. }
  214. return
  215. }
  216. if !c.agent().validateNonSTUNTraffic(c, srcAddr) {
  217. log.Warnf("Discarded message from %s, not a valid remote candidate", c.addr())
  218. return
  219. }
  220. // NOTE This will return packetio.ErrFull if the buffer ever manages to fill up.
  221. if _, err := c.agent().buffer.Write(buffer); err != nil {
  222. log.Warnf("failed to write packet")
  223. }
  224. }
  225. // close stops the recvLoop
  226. func (c *candidateBase) close() error {
  227. // If conn has never been started will be nil
  228. if c.Done() == nil {
  229. return nil
  230. }
  231. // Assert that conn has not already been closed
  232. select {
  233. case <-c.Done():
  234. return nil
  235. default:
  236. }
  237. var firstErr error
  238. // Unblock recvLoop
  239. close(c.closeCh)
  240. if err := c.conn.SetDeadline(time.Now()); err != nil {
  241. firstErr = err
  242. }
  243. // Close the conn
  244. if err := c.conn.Close(); err != nil && firstErr == nil {
  245. firstErr = err
  246. }
  247. if firstErr != nil {
  248. return firstErr
  249. }
  250. // Wait until the recvLoop is closed
  251. <-c.closedCh
  252. return nil
  253. }
  254. func (c *candidateBase) writeTo(raw []byte, dst Candidate) (int, error) {
  255. n, err := c.conn.WriteTo(raw, dst.addr())
  256. if err != nil {
  257. c.agent().log.Warnf("%s: %v", errSendPacket, err)
  258. return n, nil
  259. }
  260. c.seen(true)
  261. return n, nil
  262. }
  263. // Priority computes the priority for this ICE Candidate
  264. func (c *candidateBase) Priority() uint32 {
  265. if c.priorityOverride != 0 {
  266. return c.priorityOverride
  267. }
  268. // The local preference MUST be an integer from 0 (lowest preference) to
  269. // 65535 (highest preference) inclusive. When there is only a single IP
  270. // address, this value SHOULD be set to 65535. If there are multiple
  271. // candidates for a particular component for a particular data stream
  272. // that have the same type, the local preference MUST be unique for each
  273. // one.
  274. return (1<<24)*uint32(c.Type().Preference()) +
  275. (1<<8)*uint32(c.LocalPreference()) +
  276. uint32(256-c.Component())
  277. }
  278. // Equal is used to compare two candidateBases
  279. func (c *candidateBase) Equal(other Candidate) bool {
  280. return c.NetworkType() == other.NetworkType() &&
  281. c.Type() == other.Type() &&
  282. c.Address() == other.Address() &&
  283. c.Port() == other.Port() &&
  284. c.TCPType() == other.TCPType() &&
  285. c.RelatedAddress().Equal(other.RelatedAddress())
  286. }
  287. // String makes the candidateBase printable
  288. func (c *candidateBase) String() string {
  289. return fmt.Sprintf("%s %s %s:%d%s", c.NetworkType(), c.Type(), c.Address(), c.Port(), c.relatedAddress)
  290. }
  291. // LastReceived returns a time.Time indicating the last time
  292. // this candidate was received
  293. func (c *candidateBase) LastReceived() time.Time {
  294. lastReceived := c.lastReceived.Load()
  295. if lastReceived == nil {
  296. return time.Time{}
  297. }
  298. return lastReceived.(time.Time)
  299. }
  300. func (c *candidateBase) setLastReceived(t time.Time) {
  301. c.lastReceived.Store(t)
  302. }
  303. // LastSent returns a time.Time indicating the last time
  304. // this candidate was sent
  305. func (c *candidateBase) LastSent() time.Time {
  306. lastSent := c.lastSent.Load()
  307. if lastSent == nil {
  308. return time.Time{}
  309. }
  310. return lastSent.(time.Time)
  311. }
  312. func (c *candidateBase) setLastSent(t time.Time) {
  313. c.lastSent.Store(t)
  314. }
  315. func (c *candidateBase) seen(outbound bool) {
  316. if outbound {
  317. c.setLastSent(time.Now())
  318. } else {
  319. c.setLastReceived(time.Now())
  320. }
  321. }
  322. func (c *candidateBase) addr() net.Addr {
  323. return c.resolvedAddr
  324. }
  325. func (c *candidateBase) agent() *Agent {
  326. return c.currAgent
  327. }
  328. func (c *candidateBase) context() context.Context {
  329. return c
  330. }
  331. func (c *candidateBase) copy() (Candidate, error) {
  332. return UnmarshalCandidate(c.Marshal())
  333. }
  334. // Marshal returns the string representation of the ICECandidate
  335. func (c *candidateBase) Marshal() string {
  336. val := c.Foundation()
  337. if val == " " {
  338. val = ""
  339. }
  340. val = fmt.Sprintf("%s %d %s %d %s %d typ %s",
  341. val,
  342. c.Component(),
  343. c.NetworkType().NetworkShort(),
  344. c.Priority(),
  345. c.Address(),
  346. c.Port(),
  347. c.Type())
  348. if c.tcpType != TCPTypeUnspecified {
  349. val += fmt.Sprintf(" tcptype %s", c.tcpType.String())
  350. }
  351. if r := c.RelatedAddress(); r != nil && r.Address != "" && r.Port != 0 {
  352. val = fmt.Sprintf("%s raddr %s rport %d",
  353. val,
  354. r.Address,
  355. r.Port)
  356. }
  357. return val
  358. }
  359. // UnmarshalCandidate creates a Candidate from its string representation
  360. func UnmarshalCandidate(raw string) (Candidate, error) {
  361. split := strings.Fields(raw)
  362. // Foundation not specified: not RFC 8445 compliant but seen in the wild
  363. if len(raw) != 0 && raw[0] == ' ' {
  364. split = append([]string{" "}, split...)
  365. }
  366. if len(split) < 8 {
  367. return nil, fmt.Errorf("%w (%d)", errAttributeTooShortICECandidate, len(split))
  368. }
  369. // Foundation
  370. foundation := split[0]
  371. // Component
  372. rawComponent, err := strconv.ParseUint(split[1], 10, 16)
  373. if err != nil {
  374. return nil, fmt.Errorf("%w: %v", errParseComponent, err)
  375. }
  376. component := uint16(rawComponent)
  377. // Protocol
  378. protocol := split[2]
  379. // Priority
  380. priorityRaw, err := strconv.ParseUint(split[3], 10, 32)
  381. if err != nil {
  382. return nil, fmt.Errorf("%w: %v", errParsePriority, err)
  383. }
  384. priority := uint32(priorityRaw)
  385. // Address
  386. address := split[4]
  387. // Port
  388. rawPort, err := strconv.ParseUint(split[5], 10, 16)
  389. if err != nil {
  390. return nil, fmt.Errorf("%w: %v", errParsePort, err)
  391. }
  392. port := int(rawPort)
  393. typ := split[7]
  394. relatedAddress := ""
  395. relatedPort := 0
  396. tcpType := TCPTypeUnspecified
  397. if len(split) > 8 {
  398. split = split[8:]
  399. if split[0] == "raddr" {
  400. if len(split) < 4 {
  401. return nil, fmt.Errorf("%w: incorrect length", errParseRelatedAddr)
  402. }
  403. // RelatedAddress
  404. relatedAddress = split[1]
  405. // RelatedPort
  406. rawRelatedPort, parseErr := strconv.ParseUint(split[3], 10, 16)
  407. if parseErr != nil {
  408. return nil, fmt.Errorf("%w: %v", errParsePort, parseErr)
  409. }
  410. relatedPort = int(rawRelatedPort)
  411. } else if split[0] == "tcptype" {
  412. if len(split) < 2 {
  413. return nil, fmt.Errorf("%w: incorrect length", errParseTypType)
  414. }
  415. tcpType = NewTCPType(split[1])
  416. }
  417. }
  418. switch typ {
  419. case "host":
  420. return NewCandidateHost(&CandidateHostConfig{"", protocol, address, port, component, priority, foundation, tcpType})
  421. case "srflx":
  422. return NewCandidateServerReflexive(&CandidateServerReflexiveConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort})
  423. case "prflx":
  424. return NewCandidatePeerReflexive(&CandidatePeerReflexiveConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort})
  425. case "relay":
  426. return NewCandidateRelay(&CandidateRelayConfig{"", protocol, address, port, component, priority, foundation, relatedAddress, relatedPort, "", nil})
  427. default:
  428. }
  429. return nil, fmt.Errorf("%w (%s)", ErrUnknownCandidateTyp, typ)
  430. }