github.com/MerlinKodo/quic-go@v0.39.2/sys_conn.go (about) 1 package quic 2 3 import ( 4 "net" 5 "syscall" 6 "time" 7 8 "github.com/MerlinKodo/quic-go/internal/protocol" 9 "github.com/MerlinKodo/quic-go/internal/utils" 10 ) 11 12 // OOBCapablePacketConn is a connection that allows the reading of ECN bits from the IP header. 13 // If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will use it. 14 // In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets. 15 type OOBCapablePacketConn interface { 16 net.PacketConn 17 SyscallConn() (syscall.RawConn, error) 18 SetReadBuffer(int) error 19 ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error) 20 WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) 21 } 22 23 var _ OOBCapablePacketConn = &net.UDPConn{} 24 25 func wrapConn(pc net.PacketConn) (rawConn, error) { 26 _ = setReceiveBuffer(pc) 27 _ = setSendBuffer(pc) 28 29 conn, ok := pc.(interface { 30 SyscallConn() (syscall.RawConn, error) 31 }) 32 var supportsDF bool 33 if ok { 34 rawConn, err := conn.SyscallConn() 35 if err != nil { 36 return nil, err 37 } 38 39 if _, ok := pc.LocalAddr().(*net.UDPAddr); ok { 40 // Only set DF on sockets that we expect to be able to handle that configuration. 41 var err error 42 supportsDF, err = setDF(rawConn) 43 if err != nil { 44 return nil, err 45 } 46 } 47 } 48 c, ok := pc.(OOBCapablePacketConn) 49 if !ok { 50 utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.") 51 return &basicConn{PacketConn: pc, supportsDF: supportsDF}, nil 52 } 53 return newConn(c, supportsDF) 54 } 55 56 // The basicConn is the most trivial implementation of a rawConn. 57 // It reads a single packet from the underlying net.PacketConn. 58 // It is used when 59 // * the net.PacketConn is not a OOBCapablePacketConn, and 60 // * when the OS doesn't support OOB. 61 type basicConn struct { 62 net.PacketConn 63 supportsDF bool 64 } 65 66 var _ rawConn = &basicConn{} 67 68 func (c *basicConn) ReadPacket() (receivedPacket, error) { 69 buffer := getPacketBuffer() 70 // The packet size should not exceed protocol.MaxPacketBufferSize bytes 71 // If it does, we only read a truncated packet, which will then end up undecryptable 72 buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize] 73 n, addr, err := c.PacketConn.ReadFrom(buffer.Data) 74 if err != nil { 75 buffer.Release() 76 return receivedPacket{}, err 77 } 78 return receivedPacket{ 79 remoteAddr: addr, 80 rcvTime: time.Now(), 81 data: buffer.Data[:n], 82 buffer: buffer, 83 }, nil 84 } 85 86 func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte, gsoSize uint16, ecn protocol.ECN) (n int, err error) { 87 if gsoSize != 0 { 88 panic("cannot use GSO with a basicConn") 89 } 90 if ecn != protocol.ECNUnsupported { 91 panic("cannot use ECN with a basicConn") 92 } 93 return c.PacketConn.WriteTo(b, addr) 94 } 95 96 func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} }