diff --git a/conn_notwindows.go b/conn_notwindows.go new file mode 100644 index 000000000..bc9a2ef08 --- /dev/null +++ b/conn_notwindows.go @@ -0,0 +1,31 @@ +// +build !windows + +package quic + +import ( + "errors" + "fmt" + "net" + "syscall" +) + +func inspectReadBuffer(c net.PacketConn) (int, error) { + conn, ok := c.(interface { + SyscallConn() (syscall.RawConn, error) + }) + if !ok { + return 0, errors.New("doesn't have a SyscallConn") + } + rawConn, err := conn.SyscallConn() + if err != nil { + return 0, fmt.Errorf("couldn't get syscall.RawConn: %w", err) + } + var size int + var serr error + if err := rawConn.Control(func(fd uintptr) { + size, serr = syscall.GetsockoptInt(int(fd), syscall.SOL_SOCKET, syscall.SO_RCVBUF) + }); err != nil { + return 0, err + } + return size, serr +} diff --git a/conn_windows.go b/conn_windows.go index 2f6773cc3..936537f2d 100644 --- a/conn_windows.go +++ b/conn_windows.go @@ -7,3 +7,7 @@ import "net" func newConn(c net.PacketConn) (connection, error) { return &basicConn{PacketConn: c}, nil } + +func inspectReadBuffer(net.PacketConn) (int, error) { + return 0, nil +} diff --git a/internal/protocol/params.go b/internal/protocol/params.go index 4799b4b4f..dfa7f3d69 100644 --- a/internal/protocol/params.go +++ b/internal/protocol/params.go @@ -2,6 +2,9 @@ package protocol import "time" +// DesiredReceiveBufferSize is the kernel UDP receive buffer size that we'd like to use. +const DesiredReceiveBufferSize = (1 << 20) * 2 // 2 MB + // MaxPacketSizeIPv4 is the maximum packet size that we use for sending IPv4 packets. const MaxPacketSizeIPv4 = 1252 diff --git a/packet_handler_map.go b/packet_handler_map.go index 7a64dbd1d..3b327135f 100644 --- a/packet_handler_map.go +++ b/packet_handler_map.go @@ -6,6 +6,7 @@ import ( "crypto/sha256" "fmt" "hash" + "log" "net" "sync" "time" @@ -53,6 +54,40 @@ type packetHandlerMap struct { var _ packetHandlerManager = &packetHandlerMap{} +func setReceiveBuffer(c net.PacketConn, logger utils.Logger) { + conn, ok := c.(interface{ SetReadBuffer(int) error }) + if !ok { + logger.Debugf("Connection doesn't allow setting of receive buffer size") + return + } + size, err := inspectReadBuffer(c) + if err != nil { + log.Printf("Failed to determine receive buffer size: %s", err) + return + } + if size >= protocol.DesiredReceiveBufferSize { + logger.Debugf("Conn has receive buffer of %d kiB (wanted: at least %d kiB)", size/1024, protocol.DesiredReceiveBufferSize/1024) + } + if err := conn.SetReadBuffer(protocol.DesiredReceiveBufferSize); err != nil { + log.Printf("Failed to increase receive buffer size: %s\n", err) + return + } + newSize, err := inspectReadBuffer(c) + if err != nil { + log.Printf("Failed to determine receive buffer size: %s", err) + return + } + if newSize == size { + log.Printf("Failed to determine receive buffer size: %s", err) + return + } + if newSize < protocol.DesiredReceiveBufferSize { + log.Printf("Failed to sufficiently increase receive buffer size. Was: %d kiB, wanted: %d kiB, got: %d kiB.", size/1024, protocol.DesiredReceiveBufferSize/1024, newSize/1024) + return + } + logger.Debugf("Increased receive buffer size to %d kiB", newSize/1024) +} + func newPacketHandlerMap( c net.PacketConn, connIDLen int, @@ -60,6 +95,7 @@ func newPacketHandlerMap( tracer logging.Tracer, logger utils.Logger, ) (packetHandlerManager, error) { + setReceiveBuffer(c, logger) conn, err := wrapConn(c) if err != nil { return nil, err @@ -81,7 +117,6 @@ func newPacketHandlerMap( if logger.Debug() { go m.logUsage() } - return m, nil }