github.com/daeuniverse/quic-go@v0.0.0-20240413031024-943f218e0810/sys_conn.go (about)

     1  package quic
     2  
     3  import (
     4  	"net"
     5  	"syscall"
     6  	"time"
     7  
     8  	"github.com/daeuniverse/quic-go/internal/protocol"
     9  	"github.com/daeuniverse/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  		return receivedPacket{}, err
    76  	}
    77  	return receivedPacket{
    78  		remoteAddr: addr,
    79  		rcvTime:    time.Now(),
    80  		data:       buffer.Data[:n],
    81  		buffer:     buffer,
    82  	}, nil
    83  }
    84  
    85  func (c *basicConn) WritePacket(b []byte, addr net.Addr, _ []byte, gsoSize uint16, ecn protocol.ECN) (n int, err error) {
    86  	if gsoSize != 0 {
    87  		panic("cannot use GSO with a basicConn")
    88  	}
    89  	if ecn != protocol.ECNUnsupported {
    90  		panic("cannot use ECN with a basicConn")
    91  	}
    92  	return c.PacketConn.WriteTo(b, addr)
    93  }
    94  
    95  func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} }