github.com/sagernet/quic-go@v0.43.1-beta.1/ech/sys_conn_buffers.go (about)

     1  package quic
     2  
     3  import (
     4  	"errors"
     5  	"fmt"
     6  	"net"
     7  	"syscall"
     8  
     9  	"github.com/sagernet/quic-go/internal/protocol"
    10  	"github.com/sagernet/quic-go/internal/utils"
    11  )
    12  
    13  //go:generate sh -c "echo '// Code generated by go generate. DO NOT EDIT.\n// Source: sys_conn_buffers.go\n' > sys_conn_buffers_write.go && sed -e 's/SetReadBuffer/SetWriteBuffer/g' -e 's/setReceiveBuffer/setSendBuffer/g' -e 's/inspectReadBuffer/inspectWriteBuffer/g' -e 's/protocol\\.DesiredReceiveBufferSize/protocol\\.DesiredSendBufferSize/g' -e 's/forceSetReceiveBuffer/forceSetSendBuffer/g' -e 's/receive buffer/send buffer/g' sys_conn_buffers.go | sed '/^\\/\\/go:generate/d' >> sys_conn_buffers_write.go"
    14  func setReceiveBuffer(c net.PacketConn) error {
    15  	conn, ok := c.(interface{ SetReadBuffer(int) error })
    16  	if !ok {
    17  		return errors.New("connection doesn't allow setting of receive buffer size. Not a *net.UDPConn?")
    18  	}
    19  
    20  	var syscallConn syscall.RawConn
    21  	if sc, ok := c.(interface {
    22  		SyscallConn() (syscall.RawConn, error)
    23  	}); ok {
    24  		var err error
    25  		syscallConn, err = sc.SyscallConn()
    26  		if err != nil {
    27  			syscallConn = nil
    28  		}
    29  	}
    30  	// The connection has a SetReadBuffer method, but we couldn't obtain a syscall.RawConn.
    31  	// This shouldn't happen for a net.UDPConn, but is possible if the connection just implements the
    32  	// net.PacketConn interface and the SetReadBuffer method.
    33  	// We have no way of checking if increasing the buffer size actually worked.
    34  	if syscallConn == nil {
    35  		return conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
    36  	}
    37  
    38  	size, err := inspectReadBuffer(syscallConn)
    39  	if err != nil {
    40  		return fmt.Errorf("failed to determine receive buffer size: %w", err)
    41  	}
    42  	if size >= protocol.DesiredReceiveBufferSize {
    43  		utils.DefaultLogger.Debugf("Conn has receive buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024)
    44  		return nil
    45  	}
    46  	// Ignore the error. We check if we succeeded by querying the buffer size afterward.
    47  	_ = conn.SetReadBuffer(protocol.DesiredReceiveBufferSize)
    48  	newSize, err := inspectReadBuffer(syscallConn)
    49  	if newSize < protocol.DesiredReceiveBufferSize {
    50  		// Try again with RCVBUFFORCE on Linux
    51  		_ = forceSetReceiveBuffer(syscallConn, protocol.DesiredReceiveBufferSize)
    52  		newSize, err = inspectReadBuffer(syscallConn)
    53  		if err != nil {
    54  			return fmt.Errorf("failed to determine receive buffer size: %w", err)
    55  		}
    56  	}
    57  	if err != nil {
    58  		return fmt.Errorf("failed to determine receive buffer size: %w", err)
    59  	}
    60  	if newSize == size {
    61  		return fmt.Errorf("failed to increase receive buffer size (wanted: %d kiB, got %d kiB)", protocol.DesiredReceiveBufferSize/1024, newSize/1024)
    62  	}
    63  	if newSize < protocol.DesiredReceiveBufferSize {
    64  		return fmt.Errorf("failed to sufficiently increase receive buffer size (was: %d kiB, wanted: %d kiB, got: %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024, newSize/1024)
    65  	}
    66  	utils.DefaultLogger.Debugf("Increased receive buffer size to %d kiB", newSize/1024)
    67  	return nil
    68  }