forked from quic-go/quic-go
introduce a OptimizeConn function to manually enable UDP optimizations
This commit is contained in:
19
sys_conn.go
19
sys_conn.go
@@ -15,13 +15,30 @@ import (
|
||||
type OOBCapablePacketConn interface {
|
||||
net.PacketConn
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
SetReadBuffer(int) error
|
||||
ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error)
|
||||
WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error)
|
||||
}
|
||||
|
||||
var _ OOBCapablePacketConn = &net.UDPConn{}
|
||||
|
||||
func wrapConn(pc net.PacketConn) (rawConn, error) {
|
||||
// OptimizeConn takes a net.PacketConn and attempts to enable various optimizations that will improve QUIC performance:
|
||||
// 1. It enables the Don't Fragment (DF) bit on the IP header.
|
||||
// This allows us to do DPLPMTUD (Path MTU Discovery).
|
||||
// 2. It enables reading of the ECN bits from the IP header.
|
||||
// This allows the remote node to speed up its loss detection and recovery.
|
||||
// 3. It uses batched syscalls (recvmmsg) to more efficiently receive packets from the socket.
|
||||
//
|
||||
// For this to work, the connection needs to implement the OOBCapablePacketConn interface (as a *net.UDPConn does).
|
||||
func OptimizeConn(c net.PacketConn) (net.PacketConn, error) {
|
||||
return wrapConn(c)
|
||||
}
|
||||
|
||||
func wrapConn(pc net.PacketConn) (interface {
|
||||
net.PacketConn
|
||||
rawConn
|
||||
}, error,
|
||||
) {
|
||||
conn, ok := pc.(interface {
|
||||
SyscallConn() (syscall.RawConn, error)
|
||||
})
|
||||
|
||||
@@ -4,7 +4,7 @@ package quic
|
||||
|
||||
import "net"
|
||||
|
||||
func newConn(c net.PacketConn, supportsDF bool) (rawConn, error) {
|
||||
func newConn(c net.PacketConn, supportsDF bool) (*basicConn, error) {
|
||||
return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"golang.org/x/sys/windows"
|
||||
)
|
||||
|
||||
func newConn(c OOBCapablePacketConn, supportsDF bool) (rawConn, error) {
|
||||
func newConn(c OOBCapablePacketConn, supportsDF bool) (*basicConn, error) {
|
||||
return &basicConn{PacketConn: c, supportsDF: supportsDF}, nil
|
||||
}
|
||||
|
||||
|
||||
21
transport.go
21
transport.go
@@ -30,10 +30,8 @@ type Transport struct {
|
||||
// A single net.PacketConn can only be handled by one Transport.
|
||||
// Bad things will happen if passed to multiple Transports.
|
||||
//
|
||||
// If the connection satisfies the OOBCapablePacketConn interface
|
||||
// (as a net.UDPConn does), ECN and packet info support will be enabled.
|
||||
// In this case, optimized syscalls might be used, skipping the
|
||||
// ReadFrom and WriteTo calls to read / write packets.
|
||||
// If not done by the user, the connection is passed through OptimizeConn to enable a number of optimizations.
|
||||
// After passing the connection to the Transport, its invalid to call ReadFrom and WriteTo.
|
||||
Conn net.PacketConn
|
||||
|
||||
// The length of the connection ID in bytes.
|
||||
@@ -180,11 +178,18 @@ func (t *Transport) init(isServer bool) error {
|
||||
t.initOnce.Do(func() {
|
||||
getMultiplexer().AddConn(t.Conn)
|
||||
|
||||
conn, err := wrapConn(t.Conn)
|
||||
if err != nil {
|
||||
t.initErr = err
|
||||
return
|
||||
var conn rawConn
|
||||
if c, ok := t.Conn.(rawConn); ok {
|
||||
conn = c
|
||||
} else {
|
||||
var err error
|
||||
conn, err = wrapConn(t.Conn)
|
||||
if err != nil {
|
||||
t.initErr = err
|
||||
return
|
||||
}
|
||||
}
|
||||
t.conn = conn
|
||||
|
||||
t.logger = utils.DefaultLogger // TODO: make this configurable
|
||||
t.conn = conn
|
||||
|
||||
Reference in New Issue
Block a user