github.com/tumi8/quic-go@v0.37.4-tum/sys_conn.go (about)

     1  package quic
     2  
     3  import (
     4  	"fmt"
     5  	"log"
     6  	"net"
     7  	"os"
     8  	"strconv"
     9  	"strings"
    10  	"syscall"
    11  	"time"
    12  
    13  	"github.com/tumi8/quic-go/noninternal/protocol"
    14  	"github.com/tumi8/quic-go/noninternal/utils"
    15  )
    16  
    17  // OOBCapablePacketConn is a connection that allows the reading of ECN bits from the IP header.
    18  // If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will use it.
    19  // In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets.
    20  type OOBCapablePacketConn interface {
    21  	net.PacketConn
    22  	SyscallConn() (syscall.RawConn, error)
    23  	SetReadBuffer(int) error
    24  	ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
    25  	WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
    26  }
    27  
    28  var _ OOBCapablePacketConn = &net.UDPConn{}
    29  
    30  func wrapConn(pc net.PacketConn) (rawConn, error) {
    31  	if err := setReceiveBuffer(pc); err != nil {
    32  		if !strings.Contains(err.Error(), "use of closed network connection") {
    33  			setBufferWarningOnce.Do(func() {
    34  				if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
    35  					return
    36  				}
    37  				log.Printf("%s. See https://github.com/tumi8/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
    38  			})
    39  		}
    40  	}
    41  	if err := setSendBuffer(pc); err != nil {
    42  		if !strings.Contains(err.Error(), "use of closed network connection") {
    43  			setBufferWarningOnce.Do(func() {
    44  				if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable {
    45  					return
    46  				}
    47  				log.Printf("%s. See https://github.com/tumi8/quic-go/wiki/UDP-Buffer-Sizes for details.", err)
    48  			})
    49  		}
    50  	}
    51  
    52  	conn, ok := pc.(interface {
    53  		SyscallConn() (syscall.RawConn, error)
    54  	})
    55  	var supportsDF bool
    56  	if ok {
    57  		rawConn, err := conn.SyscallConn()
    58  		if err != nil {
    59  			return nil, err
    60  		}
    61  
    62  		if _, ok := pc.LocalAddr().(*net.UDPAddr); ok {
    63  			// Only set DF on sockets that we expect to be able to handle that configuration.
    64  			var err error
    65  			supportsDF, err = setDF(rawConn)
    66  			if err != nil {
    67  				return nil, err
    68  			}
    69  		}
    70  	}
    71  	c, ok := pc.(OOBCapablePacketConn)
    72  	if !ok {
    73  		utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.")
    74  		return &basicConn{PacketConn: pc, supportsDF: supportsDF}, nil
    75  	}
    76  	return newConn(c, supportsDF)
    77  }
    78  
    79  // The basicConn is the most trivial implementation of a rawConn.
    80  // It reads a single packet from the underlying net.PacketConn.
    81  // It is used when
    82  // * the net.PacketConn is not a OOBCapablePacketConn, and
    83  // * when the OS doesn't support OOB.
    84  type basicConn struct {
    85  	net.PacketConn
    86  	supportsDF bool
    87  }
    88  
    89  var _ rawConn = &basicConn{}
    90  
    91  func (c *basicConn) ReadPacket() (receivedPacket, error) {
    92  	buffer := getPacketBuffer()
    93  	// The packet size should not exceed protocol.MaxPacketBufferSize bytes
    94  	// If it does, we only read a truncated packet, which will then end up undecryptable
    95  	buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize]
    96  	n, addr, err := c.PacketConn.ReadFrom(buffer.Data)
    97  	if err != nil {
    98  		return receivedPacket{}, err
    99  	}
   100  	return receivedPacket{
   101  		remoteAddr: addr,
   102  		rcvTime:    time.Now(),
   103  		data:       buffer.Data[:n],
   104  		buffer:     buffer,
   105  	}, nil
   106  }
   107  
   108  func (c *basicConn) WritePacket(b []byte, packetSize uint16, addr net.Addr, _ []byte) (n int, err error) {
   109  	if uint16(len(b)) != packetSize {
   110  		panic(fmt.Sprintf("inconsistent length. got: %d. expected %d", packetSize, len(b)))
   111  	}
   112  	return c.PacketConn.WriteTo(b, addr)
   113  }
   114  
   115  func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} }