1package quic 2 3import ( 4 "io" 5 "net" 6 "syscall" 7 "time" 8 9 "github.com/lucas-clemente/quic-go/internal/protocol" 10 "github.com/lucas-clemente/quic-go/internal/utils" 11) 12 13type connection interface { 14 ReadPacket() (*receivedPacket, error) 15 WritePacket(b []byte, addr net.Addr, oob []byte) (int, error) 16 LocalAddr() net.Addr 17 io.Closer 18} 19 20// If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will read the ECN bits from the IP header. 21// In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets. 22type OOBCapablePacketConn interface { 23 net.PacketConn 24 SyscallConn() (syscall.RawConn, error) 25 ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error) 26 WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) 27} 28 29var _ OOBCapablePacketConn = &net.UDPConn{} 30 31func wrapConn(pc net.PacketConn) (connection, error) { 32 c, ok := pc.(OOBCapablePacketConn) 33 if !ok { 34 utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.") 35 return &basicConn{PacketConn: pc}, nil 36 } 37 return newConn(c) 38} 39 40type basicConn struct { 41 net.PacketConn 42} 43 44var _ connection = &basicConn{} 45 46func (c *basicConn) ReadPacket() (*receivedPacket, error) { 47 buffer := getPacketBuffer() 48 // The packet size should not exceed protocol.MaxPacketBufferSize bytes 49 // If it does, we only read a truncated packet, which will then end up undecryptable 50 buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize] 51 n, addr, err := c.PacketConn.ReadFrom(buffer.Data) 52 if err != nil { 53 return nil, err 54 } 55 return &receivedPacket{ 56 remoteAddr: addr, 57 rcvTime: time.Now(), 58 data: buffer.Data[:n], 59 buffer: buffer, 60 }, nil 61} 62 63func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte) (n int, err error) { 64 return c.PacketConn.WriteTo(b, addr) 65} 66