package quic
import (
"io"
"log"
"net"
"os"
"strconv"
"strings"
"syscall"
"time"
"github.com/quic-go/quic-go/internal/monotime"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/utils"
)
type connCapabilities struct {
DF bool
GSO bool
ECN bool
}
type rawConn interface {
ReadPacket() (receivedPacket , error )
WritePacket(b []byte , addr net .Addr , packetInfoOOB []byte , gsoSize uint16 , ecn protocol .ECN ) (int , error )
LocalAddr() net .Addr
SetReadDeadline(time .Time ) error
io .Closer
capabilities() connCapabilities
}
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 ) {
if err := setReceiveBuffer (pc ); err != nil {
if !strings .Contains (err .Error(), "use of closed network connection" ) {
setBufferWarningOnce .Do (func () {
if disable , _ := strconv .ParseBool (os .Getenv ("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING" )); disable {
return
}
log .Printf ("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details." , err )
})
}
}
if err := setSendBuffer (pc ); err != nil {
if !strings .Contains (err .Error(), "use of closed network connection" ) {
setBufferWarningOnce .Do (func () {
if disable , _ := strconv .ParseBool (os .Getenv ("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING" )); disable {
return
}
log .Printf ("%s. See https://github.com/quic-go/quic-go/wiki/UDP-Buffer-Sizes for details." , err )
})
}
}
conn , ok := pc .(interface {
SyscallConn () (syscall .RawConn , error )
})
var supportsDF bool
if ok {
rawConn , err := conn .SyscallConn ()
if err != nil {
return nil , err
}
if _ , ok := pc .LocalAddr ().(*net .UDPAddr ); ok {
var err error
supportsDF , err = setDF (rawConn )
if err != nil {
return nil , err
}
}
}
c , ok := pc .(OOBCapablePacketConn )
if !ok {
utils .DefaultLogger .Infof ("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections." )
return &basicConn {PacketConn : pc , supportsDF : supportsDF }, nil
}
return newConn (c , supportsDF )
}
type basicConn struct {
net .PacketConn
supportsDF bool
}
var _ rawConn = &basicConn {}
func (c *basicConn ) ReadPacket () (receivedPacket , error ) {
buffer := getPacketBuffer ()
buffer .Data = buffer .Data [:protocol .MaxPacketBufferSize ]
n , addr , err := c .ReadFrom (buffer .Data )
if err != nil {
return receivedPacket {}, err
}
return receivedPacket {
remoteAddr : addr ,
rcvTime : monotime .Now (),
data : buffer .Data [:n ],
buffer : buffer ,
}, nil
}
func (c *basicConn ) WritePacket (b []byte , addr net .Addr , _ []byte , gsoSize uint16 , ecn protocol .ECN ) (n int , err error ) {
if gsoSize != 0 {
panic ("cannot use GSO with a basicConn" )
}
if ecn != protocol .ECNUnsupported {
panic ("cannot use ECN with a basicConn" )
}
return c .WriteTo (b , addr )
}
func (c *basicConn ) capabilities () connCapabilities { return connCapabilities {DF : c .supportsDF } }
The pages are generated with Golds v0.8.4 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @zigo_101 (reachable from the left QR code) to get the latest news of Golds .