e2e_lossy_test.go 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. // SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
  2. // SPDX-License-Identifier: MIT
  3. package e2e
  4. import (
  5. "crypto/tls"
  6. "fmt"
  7. "math/rand"
  8. "testing"
  9. "time"
  10. "github.com/pion/dtls/v2"
  11. "github.com/pion/dtls/v2/pkg/crypto/selfsign"
  12. transportTest "github.com/pion/transport/v2/test"
  13. )
  14. const (
  15. flightInterval = time.Millisecond * 100
  16. lossyTestTimeout = 30 * time.Second
  17. )
  18. /*
  19. DTLS Client/Server over a lossy transport, just asserts it can handle at increasing increments
  20. */
  21. func TestPionE2ELossy(t *testing.T) {
  22. // Check for leaking routines
  23. report := transportTest.CheckRoutines(t)
  24. defer report()
  25. type runResult struct {
  26. dtlsConn *dtls.Conn
  27. err error
  28. }
  29. serverCert, err := selfsign.GenerateSelfSigned()
  30. if err != nil {
  31. t.Fatal(err)
  32. }
  33. clientCert, err := selfsign.GenerateSelfSigned()
  34. if err != nil {
  35. t.Fatal(err)
  36. }
  37. for _, test := range []struct {
  38. LossChanceRange int
  39. DoClientAuth bool
  40. CipherSuites []dtls.CipherSuiteID
  41. MTU int
  42. }{
  43. {
  44. LossChanceRange: 0,
  45. },
  46. {
  47. LossChanceRange: 10,
  48. },
  49. {
  50. LossChanceRange: 20,
  51. },
  52. {
  53. LossChanceRange: 50,
  54. },
  55. {
  56. LossChanceRange: 0,
  57. DoClientAuth: true,
  58. },
  59. {
  60. LossChanceRange: 10,
  61. DoClientAuth: true,
  62. },
  63. {
  64. LossChanceRange: 20,
  65. DoClientAuth: true,
  66. },
  67. {
  68. LossChanceRange: 50,
  69. DoClientAuth: true,
  70. },
  71. {
  72. LossChanceRange: 0,
  73. CipherSuites: []dtls.CipherSuiteID{dtls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
  74. },
  75. {
  76. LossChanceRange: 10,
  77. CipherSuites: []dtls.CipherSuiteID{dtls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
  78. },
  79. {
  80. LossChanceRange: 20,
  81. CipherSuites: []dtls.CipherSuiteID{dtls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
  82. },
  83. {
  84. LossChanceRange: 50,
  85. CipherSuites: []dtls.CipherSuiteID{dtls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
  86. },
  87. {
  88. LossChanceRange: 10,
  89. MTU: 100,
  90. DoClientAuth: true,
  91. },
  92. {
  93. LossChanceRange: 20,
  94. MTU: 100,
  95. DoClientAuth: true,
  96. },
  97. {
  98. LossChanceRange: 50,
  99. MTU: 100,
  100. DoClientAuth: true,
  101. },
  102. } {
  103. name := fmt.Sprintf("Loss%d_MTU%d", test.LossChanceRange, test.MTU)
  104. if test.DoClientAuth {
  105. name += "_WithCliAuth"
  106. }
  107. for _, ciph := range test.CipherSuites {
  108. name += "_With" + ciph.String()
  109. }
  110. test := test
  111. t.Run(name, func(t *testing.T) {
  112. // Limit runtime in case of deadlocks
  113. lim := transportTest.TimeOut(lossyTestTimeout + time.Second)
  114. defer lim.Stop()
  115. rand.Seed(time.Now().UTC().UnixNano())
  116. chosenLoss := rand.Intn(9) + test.LossChanceRange //nolint:gosec
  117. serverDone := make(chan runResult)
  118. clientDone := make(chan runResult)
  119. br := transportTest.NewBridge()
  120. if err = br.SetLossChance(chosenLoss); err != nil {
  121. t.Fatal(err)
  122. }
  123. go func() {
  124. cfg := &dtls.Config{
  125. FlightInterval: flightInterval,
  126. CipherSuites: test.CipherSuites,
  127. InsecureSkipVerify: true,
  128. MTU: test.MTU,
  129. }
  130. if test.DoClientAuth {
  131. cfg.Certificates = []tls.Certificate{clientCert}
  132. }
  133. client, startupErr := dtls.Client(br.GetConn0(), cfg)
  134. clientDone <- runResult{client, startupErr}
  135. }()
  136. go func() {
  137. cfg := &dtls.Config{
  138. Certificates: []tls.Certificate{serverCert},
  139. FlightInterval: flightInterval,
  140. MTU: test.MTU,
  141. }
  142. if test.DoClientAuth {
  143. cfg.ClientAuth = dtls.RequireAnyClientCert
  144. }
  145. server, startupErr := dtls.Server(br.GetConn1(), cfg)
  146. serverDone <- runResult{server, startupErr}
  147. }()
  148. testTimer := time.NewTimer(lossyTestTimeout)
  149. var serverConn, clientConn *dtls.Conn
  150. defer func() {
  151. if serverConn != nil {
  152. if err = serverConn.Close(); err != nil {
  153. t.Error(err)
  154. }
  155. }
  156. if clientConn != nil {
  157. if err = clientConn.Close(); err != nil {
  158. t.Error(err)
  159. }
  160. }
  161. }()
  162. for {
  163. if serverConn != nil && clientConn != nil {
  164. break
  165. }
  166. br.Tick()
  167. select {
  168. case serverResult := <-serverDone:
  169. if serverResult.err != nil {
  170. t.Errorf("Fail, serverError: clientComplete(%t) serverComplete(%t) LossChance(%d) error(%v)", clientConn != nil, serverConn != nil, chosenLoss, serverResult.err)
  171. return
  172. }
  173. serverConn = serverResult.dtlsConn
  174. case clientResult := <-clientDone:
  175. if clientResult.err != nil {
  176. t.Errorf("Fail, clientError: clientComplete(%t) serverComplete(%t) LossChance(%d) error(%v)", clientConn != nil, serverConn != nil, chosenLoss, clientResult.err)
  177. return
  178. }
  179. clientConn = clientResult.dtlsConn
  180. case <-testTimer.C:
  181. t.Errorf("Test expired: clientComplete(%t) serverComplete(%t) LossChance(%d)", clientConn != nil, serverConn != nil, chosenLoss)
  182. return
  183. case <-time.After(10 * time.Millisecond):
  184. }
  185. }
  186. })
  187. }
  188. }