mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-03 20:27:35 +03:00
uTLS is not yet bumped to the new version, so this commit breaks the dependencies relationship by getting rid of the local replace.
80 lines
2.2 KiB
Go
80 lines
2.2 KiB
Go
//go:build linux
|
|
|
|
package quic
|
|
|
|
import (
|
|
"errors"
|
|
"log"
|
|
"os"
|
|
"strconv"
|
|
"syscall"
|
|
"unsafe"
|
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
"github.com/refraction-networking/uquic/internal/utils"
|
|
)
|
|
|
|
func setDF(rawConn syscall.RawConn) (bool, error) {
|
|
// Enabling IP_MTU_DISCOVER will force the kernel to return "sendto: message too long"
|
|
// and the datagram will not be fragmented
|
|
var errDFIPv4, errDFIPv6 error
|
|
if err := rawConn.Control(func(fd uintptr) {
|
|
errDFIPv4 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IP, unix.IP_MTU_DISCOVER, unix.IP_PMTUDISC_DO)
|
|
errDFIPv6 = unix.SetsockoptInt(int(fd), unix.IPPROTO_IPV6, unix.IPV6_MTU_DISCOVER, unix.IPV6_PMTUDISC_DO)
|
|
}); err != nil {
|
|
return false, err
|
|
}
|
|
switch {
|
|
case errDFIPv4 == nil && errDFIPv6 == nil:
|
|
utils.DefaultLogger.Debugf("Setting DF for IPv4 and IPv6.")
|
|
case errDFIPv4 == nil && errDFIPv6 != nil:
|
|
utils.DefaultLogger.Debugf("Setting DF for IPv4.")
|
|
case errDFIPv4 != nil && errDFIPv6 == nil:
|
|
utils.DefaultLogger.Debugf("Setting DF for IPv6.")
|
|
case errDFIPv4 != nil && errDFIPv6 != nil:
|
|
return false, errors.New("setting DF failed for both IPv4 and IPv6")
|
|
}
|
|
return true, nil
|
|
}
|
|
|
|
func maybeSetGSO(rawConn syscall.RawConn) bool {
|
|
enable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_ENABLE_GSO"))
|
|
if !enable {
|
|
return false
|
|
}
|
|
|
|
var setErr error
|
|
if err := rawConn.Control(func(fd uintptr) {
|
|
setErr = unix.SetsockoptInt(int(fd), syscall.IPPROTO_UDP, unix.UDP_SEGMENT, 1)
|
|
}); err != nil {
|
|
setErr = err
|
|
}
|
|
if setErr != nil {
|
|
log.Println("failed to enable GSO")
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func isSendMsgSizeErr(err error) bool {
|
|
// https://man7.org/linux/man-pages/man7/udp.7.html
|
|
return errors.Is(err, unix.EMSGSIZE)
|
|
}
|
|
|
|
func isRecvMsgSizeErr(err error) bool { return false }
|
|
|
|
func appendUDPSegmentSizeMsg(b []byte, size uint16) []byte {
|
|
startLen := len(b)
|
|
const dataLen = 2 // payload is a uint16
|
|
b = append(b, make([]byte, unix.CmsgSpace(dataLen))...)
|
|
h := (*unix.Cmsghdr)(unsafe.Pointer(&b[startLen]))
|
|
h.Level = syscall.IPPROTO_UDP
|
|
h.Type = unix.UDP_SEGMENT
|
|
h.SetLen(unix.CmsgLen(dataLen))
|
|
|
|
// UnixRights uses the private `data` method, but I *think* this achieves the same goal.
|
|
offset := startLen + unix.CmsgSpace(0)
|
|
*(*uint16)(unsafe.Pointer(&b[offset])) = size
|
|
return b
|
|
}
|