github.com/sagernet/quic-go@v0.43.1-beta.1/send_conn.go (about) 1 package quic 2 3 import ( 4 "net" 5 "sync/atomic" 6 7 "github.com/sagernet/quic-go/internal/protocol" 8 "github.com/sagernet/quic-go/internal/utils" 9 ) 10 11 // A sendConn allows sending using a simple Write() on a non-connected packet conn. 12 type sendConn interface { 13 Write(b []byte, gsoSize uint16, ecn protocol.ECN) error 14 Close() error 15 LocalAddr() net.Addr 16 RemoteAddr() net.Addr 17 SetRemoteAddr(net.Addr) 18 19 capabilities() connCapabilities 20 } 21 22 type sconn struct { 23 rawConn 24 25 localAddr net.Addr 26 remoteAddr atomic.Value 27 28 logger utils.Logger 29 30 packetInfoOOB []byte 31 // If GSO enabled, and we receive a GSO error for this remote address, GSO is disabled. 32 gotGSOError bool 33 // Used to catch the error sometimes returned by the first sendmsg call on Linux, 34 // see https://github.com/golang/go/issues/63322. 35 wroteFirstPacket bool 36 } 37 38 var _ sendConn = &sconn{} 39 40 func newSendConn(c rawConn, remote net.Addr, info packetInfo, logger utils.Logger) *sconn { 41 localAddr := c.LocalAddr() 42 if info.addr.IsValid() { 43 if udpAddr, ok := localAddr.(*net.UDPAddr); ok { 44 addrCopy := *udpAddr 45 addrCopy.IP = info.addr.AsSlice() 46 localAddr = &addrCopy 47 } 48 } 49 50 oob := info.OOB() 51 // increase oob slice capacity, so we can add the UDP_SEGMENT and ECN control messages without allocating 52 l := len(oob) 53 oob = append(oob, make([]byte, 64)...)[:l] 54 sc := &sconn{ 55 rawConn: c, 56 localAddr: localAddr, 57 remoteAddr: atomic.Value{}, 58 packetInfoOOB: oob, 59 logger: logger, 60 } 61 sc.SetRemoteAddr(remote) 62 return sc 63 } 64 65 func (c *sconn) Write(p []byte, gsoSize uint16, ecn protocol.ECN) error { 66 remoteAddr := c.remoteAddr.Load().(net.Addr) 67 _, err := c.WritePacket(p, remoteAddr, c.packetInfoOOB, gsoSize, ecn) 68 if err != nil && isGSOError(err) { 69 // disable GSO for future calls 70 c.gotGSOError = true 71 if c.logger.Debug() { 72 c.logger.Debugf("GSO failed when sending to %s", remoteAddr) 73 } 74 // send out the packets one by one 75 for len(p) > 0 { 76 l := len(p) 77 if l > int(gsoSize) { 78 l = int(gsoSize) 79 } 80 if _, err := c.WritePacket(p[:l], remoteAddr, c.packetInfoOOB, 0, ecn); err != nil { 81 return err 82 } 83 p = p[l:] 84 } 85 return nil 86 } 87 return err 88 } 89 90 func (c *sconn) writePacket(p []byte, addr net.Addr, oob []byte, gsoSize uint16, ecn protocol.ECN) error { 91 _, err := c.WritePacket(p, addr, oob, gsoSize, ecn) 92 if err != nil && !c.wroteFirstPacket && isPermissionError(err) { 93 _, err = c.WritePacket(p, addr, oob, gsoSize, ecn) 94 } 95 c.wroteFirstPacket = true 96 return err 97 } 98 99 func (c *sconn) capabilities() connCapabilities { 100 capabilities := c.rawConn.capabilities() 101 if capabilities.GSO { 102 capabilities.GSO = !c.gotGSOError 103 } 104 return capabilities 105 } 106 107 func (c *sconn) RemoteAddr() net.Addr { return c.remoteAddr.Load().(net.Addr) } 108 func (c *sconn) LocalAddr() net.Addr { return c.localAddr } 109 110 func (c *sconn) SetRemoteAddr(addr net.Addr) { 111 if addr == nil { 112 return 113 } 114 c.remoteAddr.Store(addr) 115 }