github.com/tumi8/quic-go@v0.37.4-tum/sys_conn_oob_test.go (about) 1 //go:build darwin || linux || freebsd 2 3 package quic 4 5 import ( 6 "fmt" 7 "net" 8 "time" 9 10 "golang.org/x/net/ipv4" 11 "golang.org/x/sys/unix" 12 13 "github.com/tumi8/quic-go/noninternal/protocol" 14 "github.com/tumi8/quic-go/noninternal/utils" 15 16 "github.com/golang/mock/gomock" 17 . "github.com/onsi/ginkgo/v2" 18 . "github.com/onsi/gomega" 19 ) 20 21 var _ = Describe("OOB Conn Test", func() { 22 runServer := func(network, address string) (*net.UDPConn, <-chan receivedPacket) { 23 addr, err := net.ResolveUDPAddr(network, address) 24 Expect(err).ToNot(HaveOccurred()) 25 udpConn, err := net.ListenUDP(network, addr) 26 Expect(err).ToNot(HaveOccurred()) 27 oobConn, err := newConn(udpConn, true) 28 Expect(err).ToNot(HaveOccurred()) 29 Expect(oobConn.capabilities().DF).To(BeTrue()) 30 31 packetChan := make(chan receivedPacket) 32 go func() { 33 defer GinkgoRecover() 34 for { 35 p, err := oobConn.ReadPacket() 36 if err != nil { 37 return 38 } 39 packetChan <- p 40 } 41 }() 42 43 return udpConn, packetChan 44 } 45 46 Context("ECN conn", func() { 47 sendPacketWithECN := func(network string, addr *net.UDPAddr, setECN func(uintptr)) net.Addr { 48 conn, err := net.DialUDP(network, nil, addr) 49 ExpectWithOffset(1, err).ToNot(HaveOccurred()) 50 rawConn, err := conn.SyscallConn() 51 ExpectWithOffset(1, err).ToNot(HaveOccurred()) 52 ExpectWithOffset(1, rawConn.Control(func(fd uintptr) { 53 setECN(fd) 54 })).To(Succeed()) 55 _, err = conn.Write([]byte("foobar")) 56 ExpectWithOffset(1, err).ToNot(HaveOccurred()) 57 return conn.LocalAddr() 58 } 59 60 It("reads ECN flags on IPv4", func() { 61 conn, packetChan := runServer("udp4", "localhost:0") 62 defer conn.Close() 63 64 sentFrom := sendPacketWithECN( 65 "udp4", 66 conn.LocalAddr().(*net.UDPAddr), 67 func(fd uintptr) { 68 Expect(unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_TOS, 2)).To(Succeed()) 69 }, 70 ) 71 72 var p receivedPacket 73 Eventually(packetChan).Should(Receive(&p)) 74 Expect(p.rcvTime).To(BeTemporally("~", time.Now(), scaleDuration(20*time.Millisecond))) 75 Expect(p.data).To(Equal([]byte("foobar"))) 76 Expect(p.remoteAddr).To(Equal(sentFrom)) 77 Expect(p.ecn).To(Equal(protocol.ECT0)) 78 }) 79 80 It("reads ECN flags on IPv6", func() { 81 conn, packetChan := runServer("udp6", "[::]:0") 82 defer conn.Close() 83 84 sentFrom := sendPacketWithECN( 85 "udp6", 86 conn.LocalAddr().(*net.UDPAddr), 87 func(fd uintptr) { 88 Expect(unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_TCLASS, 3)).To(Succeed()) 89 }, 90 ) 91 92 var p receivedPacket 93 Eventually(packetChan).Should(Receive(&p)) 94 Expect(p.rcvTime).To(BeTemporally("~", time.Now(), scaleDuration(20*time.Millisecond))) 95 Expect(p.data).To(Equal([]byte("foobar"))) 96 Expect(p.remoteAddr).To(Equal(sentFrom)) 97 Expect(p.ecn).To(Equal(protocol.ECNCE)) 98 }) 99 100 It("reads ECN flags on a connection that supports both IPv4 and IPv6", func() { 101 conn, packetChan := runServer("udp", "0.0.0.0:0") 102 defer conn.Close() 103 port := conn.LocalAddr().(*net.UDPAddr).Port 104 105 // IPv4 106 sendPacketWithECN( 107 "udp4", 108 &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: port}, 109 func(fd uintptr) { 110 Expect(unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_TOS, 3)).To(Succeed()) 111 }, 112 ) 113 114 var p receivedPacket 115 Eventually(packetChan).Should(Receive(&p)) 116 Expect(utils.IsIPv4(p.remoteAddr.(*net.UDPAddr).IP)).To(BeTrue()) 117 Expect(p.ecn).To(Equal(protocol.ECNCE)) 118 119 // IPv6 120 sendPacketWithECN( 121 "udp6", 122 &net.UDPAddr{IP: net.IPv6loopback, Port: port}, 123 func(fd uintptr) { 124 Expect(unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_TCLASS, 1)).To(Succeed()) 125 }, 126 ) 127 128 Eventually(packetChan).Should(Receive(&p)) 129 Expect(utils.IsIPv4(p.remoteAddr.(*net.UDPAddr).IP)).To(BeFalse()) 130 Expect(p.ecn).To(Equal(protocol.ECT1)) 131 }) 132 }) 133 134 Context("Packet Info conn", func() { 135 sendPacket := func(network string, addr *net.UDPAddr) net.Addr { 136 conn, err := net.DialUDP(network, nil, addr) 137 ExpectWithOffset(1, err).ToNot(HaveOccurred()) 138 _, err = conn.Write([]byte("foobar")) 139 ExpectWithOffset(1, err).ToNot(HaveOccurred()) 140 return conn.LocalAddr() 141 } 142 143 It("reads packet info on IPv4", func() { 144 conn, packetChan := runServer("udp4", ":0") 145 defer conn.Close() 146 147 addr := conn.LocalAddr().(*net.UDPAddr) 148 ip := net.ParseIP("127.0.0.1").To4() 149 addr.IP = ip 150 sentFrom := sendPacket("udp4", addr) 151 152 var p receivedPacket 153 Eventually(packetChan).Should(Receive(&p)) 154 Expect(p.rcvTime).To(BeTemporally("~", time.Now(), scaleDuration(20*time.Millisecond))) 155 Expect(p.data).To(Equal([]byte("foobar"))) 156 Expect(p.remoteAddr).To(Equal(sentFrom)) 157 Expect(p.info.addr.IsValid()).To(BeTrue()) 158 Expect(net.IP(p.info.addr.AsSlice())).To(Equal(ip)) 159 }) 160 161 It("reads packet info on IPv6", func() { 162 conn, packetChan := runServer("udp6", ":0") 163 defer conn.Close() 164 165 addr := conn.LocalAddr().(*net.UDPAddr) 166 ip := net.ParseIP("::1") 167 addr.IP = ip 168 sentFrom := sendPacket("udp6", addr) 169 170 var p receivedPacket 171 Eventually(packetChan).Should(Receive(&p)) 172 Expect(p.rcvTime).To(BeTemporally("~", time.Now(), scaleDuration(20*time.Millisecond))) 173 Expect(p.data).To(Equal([]byte("foobar"))) 174 Expect(p.remoteAddr).To(Equal(sentFrom)) 175 Expect(p.info).To(Not(BeNil())) 176 Expect(net.IP(p.info.addr.AsSlice())).To(Equal(ip)) 177 }) 178 179 It("reads packet info on a connection that supports both IPv4 and IPv6", func() { 180 conn, packetChan := runServer("udp", ":0") 181 defer conn.Close() 182 port := conn.LocalAddr().(*net.UDPAddr).Port 183 184 // IPv4 185 ip4 := net.ParseIP("127.0.0.1") 186 sendPacket("udp4", &net.UDPAddr{IP: ip4, Port: port}) 187 188 var p receivedPacket 189 Eventually(packetChan).Should(Receive(&p)) 190 Expect(utils.IsIPv4(p.remoteAddr.(*net.UDPAddr).IP)).To(BeTrue()) 191 Expect(p.info).To(Not(BeNil())) 192 Expect(p.info.addr.Is4In6() || p.info.addr.Is4()).To(BeTrue()) 193 ip := p.info.addr.As4() 194 Expect(net.IP(ip[:])).To(Equal(ip4.To4())) 195 196 // IPv6 197 ip6 := net.ParseIP("::1") 198 sendPacket("udp6", &net.UDPAddr{IP: net.IPv6loopback, Port: port}) 199 200 Eventually(packetChan).Should(Receive(&p)) 201 Expect(utils.IsIPv4(p.remoteAddr.(*net.UDPAddr).IP)).To(BeFalse()) 202 Expect(p.info).To(Not(BeNil())) 203 Expect(net.IP(p.info.addr.AsSlice())).To(Equal(ip6)) 204 }) 205 }) 206 207 Context("Batch Reading", func() { 208 var batchConn *MockBatchConn 209 210 BeforeEach(func() { 211 batchConn = NewMockBatchConn(mockCtrl) 212 }) 213 214 It("reads multiple messages in one batch", func() { 215 const numMsgRead = batchSize/2 + 1 216 var counter int 217 batchConn.EXPECT().ReadBatch(gomock.Any(), gomock.Any()).DoAndReturn(func(ms []ipv4.Message, flags int) (int, error) { 218 Expect(ms).To(HaveLen(batchSize)) 219 for i := 0; i < numMsgRead; i++ { 220 Expect(ms[i].Buffers).To(HaveLen(1)) 221 Expect(ms[i].Buffers[0]).To(HaveLen(protocol.MaxPacketBufferSize)) 222 data := []byte(fmt.Sprintf("message %d", counter)) 223 counter++ 224 ms[i].Buffers[0] = data 225 ms[i].N = len(data) 226 } 227 return numMsgRead, nil 228 }).Times(2) 229 230 addr, err := net.ResolveUDPAddr("udp", "localhost:0") 231 Expect(err).ToNot(HaveOccurred()) 232 udpConn, err := net.ListenUDP("udp", addr) 233 Expect(err).ToNot(HaveOccurred()) 234 oobConn, err := newConn(udpConn, true) 235 Expect(err).ToNot(HaveOccurred()) 236 oobConn.batchConn = batchConn 237 238 for i := 0; i < batchSize+1; i++ { 239 p, err := oobConn.ReadPacket() 240 Expect(err).ToNot(HaveOccurred()) 241 Expect(string(p.data)).To(Equal(fmt.Sprintf("message %d", i))) 242 } 243 }) 244 }) 245 })