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