rtx_timer.go 4.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package sctp
  4. import (
  5. "math"
  6. "sync"
  7. "time"
  8. )
  9. const (
  10. rtoInitial float64 = 3.0 * 1000 // msec
  11. rtoMin float64 = 1.0 * 1000 // msec
  12. rtoMax float64 = 60.0 * 1000 // msec
  13. rtoAlpha float64 = 0.125
  14. rtoBeta float64 = 0.25
  15. maxInitRetrans uint = 8
  16. pathMaxRetrans uint = 5
  17. noMaxRetrans uint = 0
  18. )
  19. // rtoManager manages Rtx timeout values.
  20. // This is an implementation of RFC 4960 sec 6.3.1.
  21. type rtoManager struct {
  22. srtt float64
  23. rttvar float64
  24. rto float64
  25. noUpdate bool
  26. mutex sync.RWMutex
  27. }
  28. // newRTOManager creates a new rtoManager.
  29. func newRTOManager() *rtoManager {
  30. return &rtoManager{
  31. rto: rtoInitial,
  32. }
  33. }
  34. // setNewRTT takes a newly measured RTT then adjust the RTO in msec.
  35. func (m *rtoManager) setNewRTT(rtt float64) float64 {
  36. m.mutex.Lock()
  37. defer m.mutex.Unlock()
  38. if m.noUpdate {
  39. return m.srtt
  40. }
  41. if m.srtt == 0 {
  42. // First measurement
  43. m.srtt = rtt
  44. m.rttvar = rtt / 2
  45. } else {
  46. // Subsequent rtt measurement
  47. m.rttvar = (1-rtoBeta)*m.rttvar + rtoBeta*(math.Abs(m.srtt-rtt))
  48. m.srtt = (1-rtoAlpha)*m.srtt + rtoAlpha*rtt
  49. }
  50. m.rto = math.Min(math.Max(m.srtt+4*m.rttvar, rtoMin), rtoMax)
  51. return m.srtt
  52. }
  53. // getRTO simply returns the current RTO in msec.
  54. func (m *rtoManager) getRTO() float64 {
  55. m.mutex.RLock()
  56. defer m.mutex.RUnlock()
  57. return m.rto
  58. }
  59. // reset resets the RTO variables to the initial values.
  60. func (m *rtoManager) reset() {
  61. m.mutex.Lock()
  62. defer m.mutex.Unlock()
  63. if m.noUpdate {
  64. return
  65. }
  66. m.srtt = 0
  67. m.rttvar = 0
  68. m.rto = rtoInitial
  69. }
  70. // set RTO value for testing
  71. func (m *rtoManager) setRTO(rto float64, noUpdate bool) {
  72. m.mutex.Lock()
  73. defer m.mutex.Unlock()
  74. m.rto = rto
  75. m.noUpdate = noUpdate
  76. }
  77. // rtxTimerObserver is the inteface to a timer observer.
  78. // NOTE: Observers MUST NOT call start() or stop() method on rtxTimer
  79. // from within these callbacks.
  80. type rtxTimerObserver interface {
  81. onRetransmissionTimeout(timerID int, n uint)
  82. onRetransmissionFailure(timerID int)
  83. }
  84. // rtxTimer provides the retnransmission timer conforms with RFC 4960 Sec 6.3.1
  85. type rtxTimer struct {
  86. id int
  87. observer rtxTimerObserver
  88. maxRetrans uint
  89. stopFunc stopTimerLoop
  90. closed bool
  91. mutex sync.RWMutex
  92. }
  93. type stopTimerLoop func()
  94. // newRTXTimer creates a new retransmission timer.
  95. // if maxRetrans is set to 0, it will keep retransmitting until stop() is called.
  96. // (it will never make onRetransmissionFailure() callback.
  97. func newRTXTimer(id int, observer rtxTimerObserver, maxRetrans uint) *rtxTimer {
  98. return &rtxTimer{
  99. id: id,
  100. observer: observer,
  101. maxRetrans: maxRetrans,
  102. }
  103. }
  104. // start starts the timer.
  105. func (t *rtxTimer) start(rto float64) bool {
  106. t.mutex.Lock()
  107. defer t.mutex.Unlock()
  108. // this timer is already closed
  109. if t.closed {
  110. return false
  111. }
  112. // this is a noop if the timer is always running
  113. if t.stopFunc != nil {
  114. return false
  115. }
  116. // Note: rto value is intentionally not capped by RTO.Min to allow
  117. // fast timeout for the tests. Non-test code should pass in the
  118. // rto generated by rtoManager getRTO() method which caps the
  119. // value at RTO.Min or at RTO.Max.
  120. var nRtos uint
  121. cancelCh := make(chan struct{})
  122. go func() {
  123. canceling := false
  124. for !canceling {
  125. timeout := calculateNextTimeout(rto, nRtos)
  126. timer := time.NewTimer(time.Duration(timeout) * time.Millisecond)
  127. select {
  128. case <-timer.C:
  129. nRtos++
  130. if t.maxRetrans == 0 || nRtos <= t.maxRetrans {
  131. t.observer.onRetransmissionTimeout(t.id, nRtos)
  132. } else {
  133. t.stop()
  134. t.observer.onRetransmissionFailure(t.id)
  135. }
  136. case <-cancelCh:
  137. canceling = true
  138. timer.Stop()
  139. }
  140. }
  141. }()
  142. t.stopFunc = func() {
  143. close(cancelCh)
  144. }
  145. return true
  146. }
  147. // stop stops the timer.
  148. func (t *rtxTimer) stop() {
  149. t.mutex.Lock()
  150. defer t.mutex.Unlock()
  151. if t.stopFunc != nil {
  152. t.stopFunc()
  153. t.stopFunc = nil
  154. }
  155. }
  156. // closes the timer. this is similar to stop() but subsequent start() call
  157. // will fail (the timer is no longer usable)
  158. func (t *rtxTimer) close() {
  159. t.mutex.Lock()
  160. defer t.mutex.Unlock()
  161. if t.stopFunc != nil {
  162. t.stopFunc()
  163. t.stopFunc = nil
  164. }
  165. t.closed = true
  166. }
  167. // isRunning tests if the timer is running.
  168. // Debug purpose only
  169. func (t *rtxTimer) isRunning() bool {
  170. t.mutex.RLock()
  171. defer t.mutex.RUnlock()
  172. return (t.stopFunc != nil)
  173. }
  174. func calculateNextTimeout(rto float64, nRtos uint) float64 {
  175. // RFC 4096 sec 6.3.3. Handle T3-rtx Expiration
  176. // E2) For the destination address for which the timer expires, set RTO
  177. // <- RTO * 2 ("back off the timer"). The maximum value discussed
  178. // in rule C7 above (RTO.max) may be used to provide an upper bound
  179. // to this doubling operation.
  180. if nRtos < 31 {
  181. m := 1 << nRtos
  182. return math.Min(rto*float64(m), rtoMax)
  183. }
  184. return rtoMax
  185. }