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