github.com/tumi8/quic-go@v0.37.4-tum/sys_conn.go (about) 1 package quic 2 3 import ( 4 "fmt" 5 "log" 6 "net" 7 "os" 8 "strconv" 9 "strings" 10 "syscall" 11 "time" 12 13 "github.com/tumi8/quic-go/noninternal/protocol" 14 "github.com/tumi8/quic-go/noninternal/utils" 15 ) 16 17 // OOBCapablePacketConn is a connection that allows the reading of ECN bits from the IP header. 18 // If the PacketConn passed to Dial or Listen satisfies this interface, quic-go will use it. 19 // In this case, ReadMsgUDP() will be used instead of ReadFrom() to read packets. 20 type OOBCapablePacketConn interface { 21 net.PacketConn 22 SyscallConn() (syscall.RawConn, error) 23 SetReadBuffer(int) error 24 ReadMsgUDP(b, oob []byte) (n, oobn, flags int, addr *net.UDPAddr, err error) 25 WriteMsgUDP(b, oob []byte, addr *net.UDPAddr) (n, oobn int, err error) 26 } 27 28 var _ OOBCapablePacketConn = &net.UDPConn{} 29 30 func wrapConn(pc net.PacketConn) (rawConn, error) { 31 if err := setReceiveBuffer(pc); err != nil { 32 if !strings.Contains(err.Error(), "use of closed network connection") { 33 setBufferWarningOnce.Do(func() { 34 if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable { 35 return 36 } 37 log.Printf("%s. See https://github.com/tumi8/quic-go/wiki/UDP-Buffer-Sizes for details.", err) 38 }) 39 } 40 } 41 if err := setSendBuffer(pc); err != nil { 42 if !strings.Contains(err.Error(), "use of closed network connection") { 43 setBufferWarningOnce.Do(func() { 44 if disable, _ := strconv.ParseBool(os.Getenv("QUIC_GO_DISABLE_RECEIVE_BUFFER_WARNING")); disable { 45 return 46 } 47 log.Printf("%s. See https://github.com/tumi8/quic-go/wiki/UDP-Buffer-Sizes for details.", err) 48 }) 49 } 50 } 51 52 conn, ok := pc.(interface { 53 SyscallConn() (syscall.RawConn, error) 54 }) 55 var supportsDF bool 56 if ok { 57 rawConn, err := conn.SyscallConn() 58 if err != nil { 59 return nil, err 60 } 61 62 if _, ok := pc.LocalAddr().(*net.UDPAddr); ok { 63 // Only set DF on sockets that we expect to be able to handle that configuration. 64 var err error 65 supportsDF, err = setDF(rawConn) 66 if err != nil { 67 return nil, err 68 } 69 } 70 } 71 c, ok := pc.(OOBCapablePacketConn) 72 if !ok { 73 utils.DefaultLogger.Infof("PacketConn is not a net.UDPConn. Disabling optimizations possible on UDP connections.") 74 return &basicConn{PacketConn: pc, supportsDF: supportsDF}, nil 75 } 76 return newConn(c, supportsDF) 77 } 78 79 // The basicConn is the most trivial implementation of a rawConn. 80 // It reads a single packet from the underlying net.PacketConn. 81 // It is used when 82 // * the net.PacketConn is not a OOBCapablePacketConn, and 83 // * when the OS doesn't support OOB. 84 type basicConn struct { 85 net.PacketConn 86 supportsDF bool 87 } 88 89 var _ rawConn = &basicConn{} 90 91 func (c *basicConn) ReadPacket() (receivedPacket, error) { 92 buffer := getPacketBuffer() 93 // The packet size should not exceed protocol.MaxPacketBufferSize bytes 94 // If it does, we only read a truncated packet, which will then end up undecryptable 95 buffer.Data = buffer.Data[:protocol.MaxPacketBufferSize] 96 n, addr, err := c.PacketConn.ReadFrom(buffer.Data) 97 if err != nil { 98 return receivedPacket{}, err 99 } 100 return receivedPacket{ 101 remoteAddr: addr, 102 rcvTime: time.Now(), 103 data: buffer.Data[:n], 104 buffer: buffer, 105 }, nil 106 } 107 108 func (c *basicConn) WritePacket(b []byte, packetSize uint16, addr net.Addr, _ []byte) (n int, err error) { 109 if uint16(len(b)) != packetSize { 110 panic(fmt.Sprintf("inconsistent length. got: %d. expected %d", packetSize, len(b))) 111 } 112 return c.PacketConn.WriteTo(b, addr) 113 } 114 115 func (c *basicConn) capabilities() connCapabilities { return connCapabilities{DF: c.supportsDF} }