1
2
3
4
5
6
7 package quic
8
9 import (
10 "bytes"
11 "fmt"
12 "net"
13 "net/netip"
14 "runtime"
15 "testing"
16 )
17
18 func TestUDPSourceUnspecified(t *testing.T) {
19
20 runUDPTest(t, func(t *testing.T, test udpTest) {
21 t.Logf("%v", test.dstAddr)
22 data := []byte("source unspecified")
23 if err := test.src.Write(datagram{
24 b: data,
25 peerAddr: test.dstAddr,
26 }); err != nil {
27 t.Fatalf("Write: %v", err)
28 }
29 got := <-test.dgramc
30 if !bytes.Equal(got.b, data) {
31 t.Errorf("got datagram {%x}, want {%x}", got.b, data)
32 }
33 })
34 }
35
36 func TestUDPSourceSpecified(t *testing.T) {
37
38 runUDPTest(t, func(t *testing.T, test udpTest) {
39 data := []byte("source specified")
40 if err := test.src.Write(datagram{
41 b: data,
42 peerAddr: test.dstAddr,
43 localAddr: test.src.LocalAddr(),
44 }); err != nil {
45 t.Fatalf("Write: %v", err)
46 }
47 got := <-test.dgramc
48 if !bytes.Equal(got.b, data) {
49 t.Errorf("got datagram {%x}, want {%x}", got.b, data)
50 }
51 })
52 }
53
54 func TestUDPSourceInvalid(t *testing.T) {
55
56 if !udpInvalidLocalAddrIsError {
57 t.Skipf("%v: sending from invalid source succeeds", runtime.GOOS)
58 }
59 runUDPTest(t, func(t *testing.T, test udpTest) {
60 var localAddr netip.AddrPort
61 if test.src.LocalAddr().Addr().Is4() {
62 localAddr = netip.MustParseAddrPort("127.0.0.2:1234")
63 } else {
64 localAddr = netip.MustParseAddrPort("[::2]:1234")
65 }
66 data := []byte("source invalid")
67 if err := test.src.Write(datagram{
68 b: data,
69 peerAddr: test.dstAddr,
70 localAddr: localAddr,
71 }); err == nil {
72 t.Errorf("Write with invalid localAddr succeeded; want error")
73 }
74 })
75 }
76
77 func TestUDPECN(t *testing.T) {
78 if !udpECNSupport {
79 t.Skipf("%v: no ECN support", runtime.GOOS)
80 }
81
82 runUDPTest(t, func(t *testing.T, test udpTest) {
83 for _, ecn := range []ecnBits{ecnNotECT, ecnECT1, ecnECT0, ecnCE} {
84 if err := test.src.Write(datagram{
85 b: []byte{1, 2, 3, 4},
86 peerAddr: test.dstAddr,
87 ecn: ecn,
88 }); err != nil {
89 t.Fatalf("Write: %v", err)
90 }
91 got := <-test.dgramc
92 if got.ecn != ecn {
93 t.Errorf("sending ECN bits %x, got %x", ecn, got.ecn)
94 }
95 }
96 })
97 }
98
99 type udpTest struct {
100 src *netUDPConn
101 dst *netUDPConn
102 dstAddr netip.AddrPort
103 dgramc chan *datagram
104 }
105
106
107
108
109 func runUDPTest(t *testing.T, f func(t *testing.T, u udpTest)) {
110 for _, test := range []struct {
111 srcNet, srcAddr, dstNet, dstAddr string
112 }{
113 {"udp4", "127.0.0.1", "udp", ""},
114 {"udp4", "127.0.0.1", "udp4", ""},
115 {"udp4", "127.0.0.1", "udp4", "127.0.0.1"},
116 {"udp6", "::1", "udp", ""},
117 {"udp6", "::1", "udp6", ""},
118 {"udp6", "::1", "udp6", "::1"},
119 } {
120 spec := "spec"
121 if test.dstAddr == "" {
122 spec = "unspec"
123 }
124 t.Run(fmt.Sprintf("%v/%v/%v", test.srcNet, test.dstNet, spec), func(t *testing.T) {
125
126
127 switch runtime.GOOS {
128 case "dragonfly", "openbsd":
129 if test.srcNet == "udp6" && test.dstNet == "udp" {
130 t.Skipf("%v: no support for mapping IPv4 address to IPv6", runtime.GOOS)
131 }
132 case "plan9":
133 t.Skipf("ReadMsgUDP not supported on %s", runtime.GOOS)
134 }
135 if runtime.GOARCH == "wasm" && test.srcNet == "udp6" {
136 t.Skipf("%v: IPv6 tests fail when using wasm fake net", runtime.GOARCH)
137 }
138
139 srcAddr := netip.AddrPortFrom(netip.MustParseAddr(test.srcAddr), 0)
140 srcConn, err := net.ListenUDP(test.srcNet, net.UDPAddrFromAddrPort(srcAddr))
141 if err != nil {
142
143
144 t.Skipf("ListenUDP(%q, %v) = %v", test.srcNet, srcAddr, err)
145 }
146 t.Cleanup(func() { srcConn.Close() })
147 src, err := newNetUDPConn(srcConn)
148 if err != nil {
149 t.Fatalf("newNetUDPConn: %v", err)
150 }
151
152 var dstAddr netip.AddrPort
153 if test.dstAddr != "" {
154 dstAddr = netip.AddrPortFrom(netip.MustParseAddr(test.dstAddr), 0)
155 }
156 dstConn, err := net.ListenUDP(test.dstNet, net.UDPAddrFromAddrPort(dstAddr))
157 if err != nil {
158 t.Skipf("ListenUDP(%q, nil) = %v", test.dstNet, err)
159 }
160 dst, err := newNetUDPConn(dstConn)
161 if err != nil {
162 dstConn.Close()
163 t.Fatalf("newNetUDPConn: %v", err)
164 }
165
166 dgramc := make(chan *datagram)
167 go func() {
168 defer close(dgramc)
169 dst.Read(func(dgram *datagram) {
170 dgramc <- dgram
171 })
172 }()
173 t.Cleanup(func() {
174 dstConn.Close()
175 for range dgramc {
176 t.Errorf("test read unexpected datagram")
177 }
178 })
179
180 f(t, udpTest{
181 src: src,
182 dst: dst,
183 dstAddr: netip.AddrPortFrom(
184 srcAddr.Addr(),
185 dst.LocalAddr().Port(),
186 ),
187 dgramc: dgramc,
188 })
189 })
190 }
191 }
192
View as plain text